c - title tag html
¿Cómo lees las declaraciones de C? (12)
Acabo de encontrar una sección esclarecedora en " El desarrollo del lenguaje C ":
Para cada objeto de ese tipo compuesto, ya había una manera de mencionar el objeto subyacente: indexar la matriz, llamar a la función, usar el operador indirecto en el puntero. El razonamiento analógico condujo a una sintaxis de declaración para los nombres que reflejan la sintaxis de expresión en la cual los nombres aparecen típicamente. Así,
int i, *pi, **ppi;
declare un entero, un puntero a un entero, un puntero a un puntero a un entero. La sintaxis de estas declaraciones refleja la observación de que i, * pi y ** ppi producen un tipo int cuando se usan en una expresión. Similar,
int f(), *f(), (*f)();
declara una función que devuelve un entero, una función que devuelve un puntero a un entero, un puntero a una función que devuelve un entero;
int *api[10], (*pai)[10];
declara una matriz de punteros a enteros y un puntero a una matriz de enteros. En todos estos casos, la declaración de una variable se asemeja a su uso en una expresión cuyo tipo es el nombrado al principio de la declaración.
He oído hablar de algunos métodos, pero ninguno de ellos se ha estancado. Personalmente trato de evitar tipos complejos en C y trato de dividirlos en componentes typedef.
Ahora me enfrento a mantener algún código heredado de un llamado "programador de tres estrellas", y estoy teniendo dificultades para leer algo del código *** [] [].
¿Cómo se leen las declaraciones complejas de C?
Cdecl (y c ++ decl) es un programa para codificar y decodificar declaraciones de tipo C (o C ++).
http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
Cuando estaba haciendo C, hice uso de un programa llamado "cdecl". Parece que está en Ubuntu Linux en el paquete cutils o cdecl, y probablemente esté disponible en otra parte.
Este artículo explica unas 7 reglas relativamente simples que le permitirán leer cualquier declaración de C, si lo desea o necesita hacerlo manualmente: http://www.ericgiguere.com/articles/reading-c-declarations.html
- Encuentra el identificador. Este es su punto de partida. En un pedazo de papel, escriba "declare identifier as".
- Mira a la derecha. Si no hay nada allí, o hay un paréntesis derecho ")", vaya al paso 4.
Ahora está posicionado en un descriptor de matriz (corchete izquierdo) o de función (paréntesis izquierdo). Puede haber una secuencia de estos, terminando con un paréntesis derecho sin igual o al final del declarador (un punto y coma o un "=" para la inicialización). Para cada descriptor, leyendo de izquierda a derecha:
- si una matriz vacía "[]", escribe "array of"
- si una matriz con un tamaño, escriba "tamaño de matriz"
- si una función "()", escribe "función de retorno"
Deténgase en el paréntesis no coincidente o al final del declarador, lo que ocurra primero.
- Regrese a la posición inicial y mire hacia la izquierda. Si no hay nada allí, o hay un paréntesis izquierdo "(", vaya al paso 6.
- Ahora está posicionado en un descriptor de puntero, "*". Puede haber una secuencia de estos a la izquierda, que termina con un paréntesis izquierdo sin igual "(" o el inicio del declarador. Lectura de derecha a izquierda, para cada descriptor de puntero escribe "puntero a". Detener en el paréntesis no coincidente o el comienzo del declarador, lo que ocurra primero.
- En este punto, tiene una expresión entre paréntesis o el declarador completo. Si tiene una expresión entre paréntesis, considérelo como su nuevo punto de partida y vuelva al paso 2.
- Escriba el especificador de tipo. Detener.
Si está bien con una herramienta, entonces secundo la sugerencia de usar el programa cdecl
: http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
Generalmente uso lo que a veces se llama la ''regla de la mano derecha en el sentido de las agujas del reloj''. Dice así:
- Comience desde el identificador.
- Vaya a la derecha inmediata.
- Luego muévete en el sentido de las agujas del reloj y ve hacia el lado izquierdo.
- Muévete en el sentido de las agujas del reloj y ve hacia el lado derecho.
- Haga esto siempre y cuando la declaración no se haya analizado por completo.
Hay una meta-regla adicional que debe ser resuelta:
- Si hay paréntesis, complete cada nivel de paréntesis antes de mudarse.
Aquí, ''ir'' y ''moverse'' a algún lado significa leer el símbolo allí. Las reglas para eso son:
-
*
- puntero a -
()
- función que regresa -
(int, int)
- función tomando dos ints y regresando -
int
,char
, etc. -int
,char
, etc. -
[]
- matriz de -
[10]
- conjunto de diez - etc.
Entonces, por ejemplo, int* (*xyz[10])(int*, char)
se lee como:
xyz es un
matriz de diez
puntero a
función tomando un int * y un char y regresando
un int *
La solución automatizada es cdecl.
En general, declaras una variable como la usas. Por ejemplo, desreferencia un puntero p como en:
char c = * p
lo declaras de una manera similar:
char * p;
Lo mismo ocurre con los indicadores de función peluda. Declaremos que f es un buen "puntero a la función que devuelve el puntero a int" y una declaración externa solo para ser gracioso. Es un puntero a una función, así que comenzamos con:
extern * f();
Devuelve un puntero a un int, por lo que en algún lugar al frente hay
extern int * * f(); // XXX not quite yet
¿Cuál es la asociatividad correcta? Nunca puedo recordar, así que use algunos paréntesis.
extern (int *)(* f)();
Declararlo de la manera que lo usas.
Lee de derecha a izquierda.
***code[][]
- el código [] [] es una matriz multidimensional
- * code [] [] es un puntero de matriz multidimensional
- ** code [] [] es un puntero de matriz multidimensional a un puntero
- *** code [] [] es un puntero de matriz multidimensional a un puntero a un puntero
Los problemas comunes de legibilidad incluyen punteros de función y el hecho de que las matrices son realmente punteros , y que las matrices multidimensionales son realmente matrices de una sola dimensión (que en realidad son punteros). Espero que ayude a algunos.
En cualquier caso, cada vez que comprenda las declaraciones, tal vez pueda encontrar una forma de simplificarlas para que sean más legibles para el siguiente tipo.
También hay una cdecl que es bastante hábil.
Una palabra: cdecl
¡Maldita sea, derrotado por 15 segundos!
cdecl ofrece una interfaz de línea de comandos, así que pruébelo:
cdecl> explain int ***c[][]
declare c as array of array of pointer to pointer to pointer to int
otro ejemplo
explain int (*IMP)(ID,SEL)
declare IMP as pointer to function (ID, SEL) returning int
Sin embargo, hay un capítulo entero acerca de eso en el libro "C Deep Secrets", llamado "Declaraciones Unscrambling" en C.
Saludos Friedrich