¿Por qué C usa el asterisco para los punteros?
Simplemente, porque B lo hizo.
Como la memoria es una matriz lineal, es posible interpretar el valor en una celda como un índice en esta matriz, y BCPL proporciona un operador para este propósito. En el idioma original se deletreaba rv
, y más tarde !
, mientras que B usa el unario *
. Por lo tanto, si p
es una celda que contiene el índice de (o la dirección de), o apunta a) otra celda, se *p
refiere al contenido de la celda apuntada, ya sea como un valor en una expresión o como el objetivo de una asignación.
Del desarrollo del lenguaje C
Eso es. En este punto, la pregunta es tan poco interesante como "¿por qué Python 3 usa .
para llamar a un método? ¿Por qué no ->
?" Bueno ... porque Python 2 usa .
para llamar a un método.
Rara vez existe un lenguaje de la nada. Tiene influencias y se basa en algo que vino antes.
Entonces, ¿por qué B no utilizó !
para desreferenciar un puntero como lo hizo su predecesor BCPL?
Bueno, BCPL era un poco prolijo. En lugar de &&
o ||
BCPL utilizado logand
y logor
. Esto se debió a que la mayoría de los teclados no tienen teclas ∧
o ∨
no y en realidad era la palabra NEQV
(consulte el Manual de referencia de BCPL ).
B parece haber sido parcialmente inspirado para ajustar la sintaxis en lugar de tener palabras largas para todos estos operadores lógicos que los programadores hicieron con bastante frecuencia. Y así, la !
desreferencia se convirtió en *
algo que !
podría usarse para la negación lógica. Tenga en cuenta que hay una diferencia entre el *
operador unario y el *
operador binario (multiplicación).
Bueno, ¿qué hay de otras opciones, como ->
?
El ->
fue tomado para azúcar sintáctico alrededor de las deserciones de campo struct_pointer->field
que es(*struct_pointer).field
Otras opciones como <-
podrían crear análisis ambiguos. Por ejemplo:
foo <- bar
¿Es eso para ser leído como:
(foo) <- (bar)
o
(foo) < (-bar)
Es muy probable que crear un operador unario que esté compuesto por un operador binario y otro operador unario tenga problemas, ya que el segundo operador unario puede ser un prefijo para otra expresión.
Además, de nuevo es importante tratar de mantener las cosas que se escriben con frecuencia al mínimo. Me odio a tener que escribir:
int main(int argc, char->-> argv, char->-> envp)
Esto también se vuelve difícil de leer.
Otros personajes podrían haber sido posibles (el @
no se usó hasta que el Objetivo C se lo apropió ). Aunque de nuevo, esto va al núcleo de 'C utiliza *
porque B lo hizo'. ¿Por qué no usó B @
? Bueno, B no usó todos los personajes. No había ningún bpp
programa (compare cpp ) y otros caracteres estaban disponibles en B (como el #
que luego usó cpp).
Si puedo arriesgarme a adivinar por qué, es por dónde están las llaves. De un manual sobre B :
Para facilitar la manipulación de direcciones cuando parece aconsejable, B proporciona dos operadores de direcciones unarios, *
y &
. &
es el operador de dirección, también lo &x
es la dirección de x
, suponiendo que tenga una. *
es el operador de indirección; *x
significa "usar el contenido de x como una dirección".
Tenga en cuenta que &
es shift-7 y *
shift-8. Su proximidad entre sí puede haber sido una pista para el programador sobre lo que hacen ... pero eso es solo una suposición. Uno tendría que preguntarle a Ken Thompson por qué se hizo esa elección.
Entonces, ahí lo tienes. C es así porque B era. B es así porque quería cambiar de cómo era BCPL.
->
se está utilizando en el lenguaje C como operador de desreferencia, al acceder a los campos en una estructura:struct_pointer->field
que es la abreviatura de(*struct_pointer).field
.