C 2018 6.7.6.1 1 dice:
Si en la declaración “ T D1 ”, D1 tiene la forma
* type-qualifier-list opt D
y el tipo especificado para ident en la declaración “ TD ” es “ lista de tipos de declarador derivado T ”, entonces el tipo especificado para ident es “ lista de tipos de declarador derivado lista de calificadores de tipos puntero a T ”. Para cada calificador de tipo en la lista, ident es un puntero así calificado.
Esta pregunta es sobre la oración final, pero analicemos primero la primera.
Considere la declaración int * const * foo . Aquí T es int , D1 es * const * foo , type-qualifier-list es const y D es * foo .
Entonces TD es int * foo , y eso especifica "apuntador a int " para el ident foo , por lo que la lista de tipo de declarador derivado es "apuntador a". (No hay una explicación abierta de la lista de tipos de declaradores derivados en el estándar, pero 6.7.8 3, al discutir typedef , dice que "es especificado por los declaradores de D ").
Sustituir estos en la cláusula final de la primera oración nos dice que T D1 especifica que el tipo para foo es "puntero a const puntero a int ". Bien hasta ahora.
Pero luego, la oración final nos dice que para cada calificador de tipo en la lista (que es const ), ident es un puntero así calificado. Entonces dice que foo es un puntero const .
Pero no lo es; comúnmente interpretamos int * const * foo para declarar que foo es un puntero no const a un puntero const a int .
¿Es esto un error en el estándar o hay otra interpretación para la oración final?
Con T como int y D como * foo , la "T D" no proporciona el tipo de identificación T , sino un puntero a T .
La segunda parte del if :
Si... y el tipo especificado para ident en la declaración "TD" es "lista-de-tipo-de-declarador-derivado T"
parece asegurarse de que la anidación sea correcta.
Con dos estrellas, tendría que usar D2 - D1 - D antes de llegar al declarador directo.
El segundo ejemplo:
typedef int *int_ptr; const int_ptr foo; muestra lo complicado que puede llegar a ser; const está lejos de ident , pero aún así el puntero es constante, no los datos.
Las especificaciones llaman a esto una aclaración, ahora eso es un error.
Curiosamente, en la siguiente sección "6.7.6.2 Array declarators" hay una nota al pie después de la definición semántica correspondiente:
Cuando varias especificaciones de "matriz de" son adyacentes, se declara una matriz multidimensional.
No se menciona el caso de varias especificaciones de "puntero de" adyacentes. Una especie de "error".
En 1988, el "Manual de referencia" tenía el D1 y el D cambiados (!), pero por lo demás, la redacción es casi idéntica. (hay un modificador de tipo en lugar de una lista de tipo de declarador derivado ).
Los ejemplos son similares: el ejemplo principal es int *ap[] :
Aquí ap[] juega el papel de D1; una declaración "int ap[]" sería...
Con int **pp , *pp juega ese papel.
Para que conste, hay tres respuestas que fueron eliminadas por sus autores, lo que respalda la conclusión de que este aspecto del estándar C es engañoso. No creo que la otra respuesta actual coincida correctamente con el texto fuente de ejemplo ( int * const * foo ) con los símbolos en el pasaje del estándar ( T , D1 , type-qualifier-list , etc.).
Por lo tanto, concluyo que esto es de hecho un error en el estándar.
Creo que una solución es simplemente eliminar la última oración, "Para cada calificador de tipo en la lista, ident es un puntero calificado". Cualquier calificador en la lista de calificadores de tipo ya está incorporado, correctamente, en la oración anterior, y cualquier calificador dentro de D ya está incorporado en ese declarador. Así que esto parece solo una oración superflua que puede haber surgido sin darse cuenta en alguna edición.
Aquí hay una interpretación alternativa que hace que el estándar sea correcto.
Para
int * const * fooLa forma
* type-qualifier-listopt D dice que D en tu ejemplo es * foo
Así que creo que la sangría se reemplazará con * foo en lugar de solo foo
Entonces, el estándar dice que * foo es un puntero const .
lo que significa que foo es un puntero a un puntero const .