¿Puede un puntero a un tipo incompleto ser incompleto?

9

Puede int (*)[]ser un tipo incompleto?

C 2018 6.2.5 1 dice:

En varios puntos dentro de una unidad de traducción, un tipo de objeto puede estar incompleto (sin información suficiente para determinar el tamaño de los objetos de ese tipo) o completo (con información suficiente).

Por lo tanto, parece que si se conoce el tamaño de un tipo, el tipo está completo. 6.2.6.1 28 especifica que ciertos tipos de punteros deben tener los mismos tamaños (punteros a voidy caracteres, punteros a tipos compatibles, punteros a estructuras y punteros a uniones), pero los punteros a otros tipos pueden variar.

En una implementación en C donde todos los punteros, o todos los punteros a las matrices int, tienen el mismo tamaño, entonces int (*)[]se conoce el tamaño de , por lo que estaría completo. En una implementación que, por ejemplo, utiliza diferentes punteros para matrices grandes, el tamaño no se conocería, por lo que está incompleto.

Como MM señala , una estructura no debe contener un miembro con un tipo incompleto, excepto un miembro de matriz flexible final, según una restricción en 6.7.2.1 3. Esto sugiere que una implementación con un tamaño de punteros debe aceptar struct { int (*p)[]; }mientras que una implementación que tiene diferente los tamaños para tales matrices deben diagnosticar una violación de restricción. (Esto a su vez significa que dicha declaración no es parte de la estricta conformidad C.)

Eric Postpischil
fuente
6.2.5 (p22) ayuda? (¿O agrega más confusión permitiendo que el tipo incompleto se complete con una declaración posterior?)
David C. Rankin
@ DavidC.Rankin En 6.2.5 / 20 incluso se dice que los punteros son siempre tipos completos
Christophe
@LanguageLawyer: ¿Cómo sería eso relevante? La pregunta es "¿Hay una X que no sea una Y?", No "¿Hay una X que sea una Y?"
Eric Postpischil
@LanguageLawyer: el hecho de que void *esté completo muestra que se puede completar un puntero a un tipo incompleto. No muestra si un puntero a un tipo incompleto puede estar incompleto. Si uno pregunta "¿Puede un mamífero ser un elefante?", Mostrar que "Un león es un mamífero" no proporcionaría que un mamífero no puede ser un elefante. La pregunta pregunta si el conjunto X de punteros a tipo incompleto puede contener un elemento que está incompleto. Mostrar que el conjunto X de punteros a tipo incompleto contiene un elemento que está completo es irrelevante.
Eric Postpischil
@EricPostpischil Vaya. He leído mal el título como "¿Puede un puntero a un tipo incompleto sea completa ?"
Abogado de idiomas

Respuestas:

3

Una matriz de tamaño desconocido está incompleta:

Un tipo de matriz de tamaño desconocido es un tipo incompleto. Se completa, para un identificador de ese tipo, especificando el tamaño en una declaración posterior (con enlace interno o externo).

Sin int (*)[]embargo, el tipo no está incompleto: es un puntero de una matriz de inttamaño desconocido.
Y un puntero tiene un tamaño bien conocido:

printf ("Size %d\n", sizeof(int (*)[]));

6.2.5 / 23: Un tipo tiene un tamaño constante conocido si el tipo no está incompleto y no es un tipo de matriz de longitud variable.

Además, incluso puede desreferenciarlo, gracias a la semántica de la matriz:

typedef int (*T)[];
...
int a[10];
for (int i=0; i<10; i++) a[i]=i;
T p=a;
for (int i=0; i<10; i++) printf ("%d ",(*p)[i]);
printf ("\n");

Editar

Además, un puntero es siempre un tipo completo. Está escrito en negro sobre blanco en 6.2.5 / 20:

Un tipo de puntero puede derivarse de un tipo de función o un tipo de objeto, denominado tipo referenciado. Un tipo de puntero describe un objeto cuyo valor proporciona una referencia a una entidad del tipo referenciado. Un tipo de puntero derivado del tipo referenciado T a veces se denomina "puntero a T". La construcción de un tipo de puntero a partir de un tipo referenciado se denomina "derivación de tipo de puntero". Un tipo de puntero es un tipo de objeto completo.

Christophe
fuente
Creo que lo has reducido y gcc está de acuerdo. struct w / pointer to incomplete array es similar a la pregunta original que provocó la discusión.
David C. Rankin
Solo el último párrafo es relevante. El ejemplo printfsolo muestra que un puntero a una matriz incompleta está completo en la implementación en la que se ejecutó, como se indica en la pregunta: si no fuera por 6.2.5 20, citado en el último párrafo, podría no compilarse. 6.2.5 23 tampoco es relevante; nos dice que el tamaño es conocido y constante si está completo, y ya sabemos que estar completo significa que se conoce el tamaño.
Eric Postpischil
6.2.5 20 es interesante. Supongo que no estaba destinado a tener esta consecuencia, pero significa que todos los punteros para completar tipos que tienen el mismo tipo cuando están incompletos deben tener el mismo tamaño. Por ejemplo, todos los punteros a matrices intdeben tener el mismo tamaño entre sí, y todos los punteros a matrices de cierto structdeben tener el mismo tamaño entre sí, aunque quizás no todos los punteros a matrices de diferentes tipos structdeben tener el mismo tamaño como el uno al otro.
Eric Postpischil
1
@EricPostpischil tal vez el texto "Del mismo modo, los punteros a versiones calificadas o no calificadas de tipos compatibles tendrán los mismos requisitos de representación y alineación". debe interpretarse en el sentido de que T(*)[]debe tener el mismo tamaño que T(*)[5], ya que son tipos compatibles y podríamos agregar o eliminar calificadores
MM
Permitir que los tipos compatibles tengan diferentes tamaños conduciría a un montón de problemas, probablemente es un defecto que el estándar no lo descarta explícitamente
MM