Después de haber visto (¡y preguntado!) Tantas preguntas similares a
¿Qué
int (*f)(int (*a)[5])
significa en C?
e incluso viendo que habían hecho un programa para ayudar a las personas a comprender la sintaxis de C, no puedo evitar preguntarme:
¿Por qué se diseñó la sintaxis de C de esta manera?
Por ejemplo, si estuviera diseñando punteros, traduciría "un puntero a una matriz de punteros de 10 elementos" en
int*[10]* p;
y no
int* (*p)[10];
que creo que la mayoría de la gente estaría de acuerdo es mucho menos directo.
Así que me pregunto, ¿por qué la sintaxis no intuitiva? ¿Hubo un problema específico que resuelve la sintaxis (¿tal vez una ambigüedad?) Que desconozco?
cdecl
comando es muy útil para decodificar declaraciones complejas de C. También hay una interfaz web en cdecl.org .Respuestas:
Mi comprensión de la historia es que se basa en dos puntos principales ...
En primer lugar, los autores del lenguaje prefirieron hacer la sintaxis centrada en la variable en lugar de centrada en el tipo. Es decir, querían que un programador mirara la declaración y pensara "si escribo la expresión
*func(arg)
, eso dará como resultadoint
; si escribo*arg[N]
tendré un flotante" en lugar de "func
debe ser un puntero a una función que tome esto y devolviendo eso ".La entrada C en Wikipedia afirma que:
... citando p122 de K & R2 que, por desgracia, no tengo que buscar para encontrar la cotización extendida para usted.
En segundo lugar, es realmente muy difícil encontrar una sintaxis para la declaración que sea consistente cuando se trata de niveles arbitrarios de indirección. Su ejemplo podría funcionar bien para expresar el tipo que pensó de inmediato, pero ¿se adapta a una función que toma un puntero a una serie de esos tipos y devuelve algún otro desastre horrible? (Tal vez lo hace, pero ¿verificó? ¿Puedes probarlo? ).
Recuerde, parte del éxito de C se debe al hecho de que los compiladores se escribieron para muchas plataformas diferentes, por lo que podría haber sido mejor ignorar cierto grado de legibilidad en aras de facilitar la escritura de los compiladores.
Dicho esto, no soy un experto en gramática del lenguaje o redacción de compiladores. Pero sé lo suficiente como para saber que hay mucho que saber;)
fuente
Muchas de las rarezas del lenguaje C pueden explicarse por la forma en que funcionaban las computadoras cuando fue diseñado. Había cantidades muy limitadas de memoria de almacenamiento, por lo que era muy importante minimizar el tamaño de los archivos de código fuente . La práctica de programación en los años 70 y 80 consistía en asegurarse de que el código fuente contuviera la menor cantidad posible de caracteres y, preferiblemente, que no hubiera comentarios excesivos sobre el código fuente.
Por supuesto, esto es ridículo hoy en día, con espacio de almacenamiento prácticamente ilimitado en los discos duros. Pero es parte de la razón por la cual C tiene una sintaxis tan extraña en general.
Con respecto a los punteros de matriz específicamente, su segundo ejemplo debería ser
int (*p)[10];
(sí, la sintaxis es muy confusa). Quizás lo leería como "int puntero a una matriz de diez" ... lo que tiene sentido de alguna manera. Si no fuera por el paréntesis, el compilador lo interpretaría como una matriz de diez punteros, lo que le daría a la declaración un significado completamente diferente.Dado que los punteros de matriz y los punteros de función tienen una sintaxis bastante oscura en C, lo más sensato es eliminar la rareza. Quizás así:
Ejemplo oscuro:
Ejemplo no oscuro, equivalente:
Las cosas pueden volverse aún más oscuras si se trata de matrices de punteros de función. O el más oscuro de todos: funciones que devuelven punteros de función (ligeramente útiles). Si no usa typedefs para tales cosas, rápidamente se volverá loco.
fuente
Es bastante simple:
int *p
significa que*p
es un int;int a[5]
significa quea[i]
es un int.Significa que
*f
es una función,*a
es una matriz de cinco enteros, por lo quef
es una función que toma un puntero a una matriz de cinco enteros y devuelve int. Sin embargo, en C no es útil pasar un puntero a una matriz.Las declaraciones de C rara vez se complican tanto.
Además, puede aclarar usando typedefs:
fuente
typedef
,const
,volatile
, y la capacidad para inicializar las cosas dentro de declaraciones. Muchas de las molestas ambigüedades de la sintaxis de la declaración (p. Ej., Si seint const *p, *q;
deben unirconst
al tipo o al declarante) no pueden surgir en el lenguaje como se diseñó originalmente. Desearía que el lenguaje hubiera agregado dos puntos entre el tipo y el declarante, pero permitió su omisión al usar tipos integrados de "palabra reservada" sin calificadores. El significado deint: const *p,*q;
yint const *: p,*q;
habría sido claro.Creo que debe considerar * [] como operadores que están unidos a una variable. * se escribe antes de una variable, [] después.
Leamos la expresión de tipo
El elemento más interno es p, una variable, por lo tanto
significa: p es una variable.
Antes de la variable hay un *, el operador * siempre se antepone a la expresión a la que se refiere, por lo tanto,
significa: la variable p es un puntero. Sin el () el operador [] a la derecha tendría mayor prioridad, es decir
sería analizado como
El siguiente paso es []: como no hay más (), [] tiene mayor prioridad que el exterior *, por lo tanto
significa: (la variable p es un puntero) a una matriz. Luego tenemos el segundo *:
significa: ((la variable p es un puntero) a una matriz) de punteros
Finalmente tiene el operador int (un nombre de tipo), que tiene la precedencia más baja:
significa: (((la variable p es un puntero) a una matriz) de punteros) a entero.
Por lo tanto, todo el sistema se basa en expresiones de tipo con operadores, y cada operador tiene sus propias reglas de precedencia. Esto permite definir tipos muy complejos.
fuente
No es tan difícil cuando empiezas a pensar y C nunca fue un lenguaje muy fácil. Y
int*[10]* p
realmente no es más fácil queint* (*p)[10]
Y qué tipo de k estaría enint*[10]* p, k;
fuente
pointer to int
yint
ni siquiera son del mismo tipo, por lo que deben declararse por separado. Período. Escucha al hombre. Tiene 18k rep por una razón.