¿Por qué C no ofrece referencias sintácticamente transparentes como C++ y Java?
language-lawyer (5)
-
Pasar por valor suele ser más rápido que pasar por referencia y eliminar la referencia a un puntero cada vez que se desea utilizar un argumento. Como las estructuras no formaban parte de la C temprana, y más tarde era necesario pasarlas como un indicador, esto no era un gran problema.
-
Muchos compiladores antiguos no pudieron o no pudieron optimizar las desreferencias, y desreferenciar un puntero cada vez que quisiera usar un argumento sería muy lento.
-
Las computadoras viejas necesitaban un código micro-optimizado para funcionar más rápido porque los procesadores en sí no eran muy rápidos.
-
Le da al programador la libertad de elegir si desea usar un puntero o un valor para acceder a los datos.
Todo esto en conjunto probablemente equivale a por qué C usa el paso por valor.
Intenté aprender más sobre las razones históricas para pasar por valor en C. Hay una publicación de desbordamiento de pila que toca este tema en relación con C ++. Sin embargo, estoy interesado en C. Imagino que cuando se tomó esta decisión, uno podría haber optado por hacer lo que llamamos ahora "pasar por referencia". Sin embargo, esta no fue la elección hecha. ¿Existen problemas de optimización, subprocesos múltiples, etc., que entran en juego?
Intenté buscar en Google esto, pero no llegué a ningún lado. Pasar por valor presenta algunas garantías en relación con la variable que no se cambia bajo el capó. ¿Es esta la única razón? Me imagino que en aquel entonces el concepto de "copiar un objeto grueso" no era un gran problema y pasar por alto el valor incurrido. Como tal, esta podría haber sido considerada como la elección correcta. ¿Hay más de esta decisión que esta?
C siempre ha intentado ser de buen rendimiento y "cerca del metal", y las primitivas de paso (enteros / punteros / flotadores) por referencias son simplemente subóptimas (C primigenias no tenían estructuras, y cuando las obtuvieron, eran inicialmente más bien limitado y no podría pasarlos por valor o devolverlos).
Pasar por referencia implica necesariamente pasar por un puntero (implícitamente no referenciado) y si va a pasar un puntero, también puede pasar el valor directamente y evitar que el destinatario tenga que buscar el puntero.
Pasar valores directamente también ayuda al rendimiento, ya que puede atenerse a los registros y omitir la memoria mucho más lenta.
Por último, pero no menos importante, hace que sea más fácil razonar sobre el código, porque sabe que una persona que llama no puede cambiar una variable que le ha pasado por valor.
C siempre tuvo la intención de (a) estar cerca de la máquina y (b) proporcionarle mecanismos básicos con los que podría hacer cosas más complicadas, si quisiera. La elección de pasar por valor es la correcta, creo, bajo ambos criterios.
C le da una pasada por valor, pero si desea el efecto de pasar por referencia, puede hacerlo fácilmente con
&
.
(Por otra parte, si el idioma le dio pasar por referencia y desea simular el paso por valor, quedaría un poco atascado).
El uso de paso por valor también elude todos los enigmas con paso por referencia, como el comportamiento notorio (supuesto) en Fortran, donde si llamó a
f(5)
y luego modificó su argumento, terminó cambiando todos los otros 5 en el programa.
En las palabras de Kernighan y Ritchie en The C Programming Language , 1978, cláusula 1.8 "Argumentos - Llamada por valor", página 24:
La llamada por valor es un activo, sin embargo, no es un pasivo. Por lo general, conduce a programas más compactos con menos variables extrañas, porque los argumentos pueden tratarse como variables locales convenientemente inicializadas en la rutina llamada. Por ejemplo,…
... Cuando sea necesario, es posible organizar una función para modificar una variable en una rutina de llamada. La persona que llama debe proporcionar la dirección de la variable que se establecerá (técnicamente un puntero a la variable), ...
En mi opinión, la razón principal para implementar un lenguaje de complejidad tan reducida fueron los entornos soportados en los tiempos antiguos del diseño del lenguaje C. La mejor computadora asequible en 1976 para ejecutar Unix (v5, v6, v7?) Fue una pdp-11, que es una máquina con 64Kb (en las últimas se podrían separar instrucciones y datos en dos segmentos diferentes para duplicar el espacio de direcciones virtuales) de direcciones virtuales.
La necesidad de ejecutar un compilador de C con solo 64kb de espacio virtual hace que
pcc
(el compilador C portátil, el compilador de at & t unix para el pdp-11 / unix) se superponga al segmento de texto para dejar espacio para que quepa todo el código.
¡Y finalmente, piense que esos programadores tuvieron que escribir todo ese código con
ed(1)
en un teletipo de impresión!
(no pantallas planas de 40 ''con un editor de pantalla completa con caracteres de 100x180, sintaxis coloreada o efectos similares)