/ / ¿Por qué no puedo completar un nombre typedef de tipo de matriz? - C, matrices, lenguaje-abogado.

¿Por qué no puedo completar un typedef name of array type? - c, arrays, lenguaje-abogado

Los estados de la norma C (§6.2.5 p22):

Un tipo de matriz de tamaño desconocido es un tipo incompleto. Está completado, para un identificador de ese tipo, especificando el tamaño en una fecha posterior Declaración (con enlace interno o externo).

Y funciona bien en lo que respecta a las declaraciones de variables:

int a[];
int a[2]; //OK

Pero cuando añadimos typedef antes de esas declaraciones el compilador se queja (también cambié el nombre):

typedef int t[];
typedef int t[2]; //redefinition with different type

Sin embargo, no nos quejamos cuando estamos completando una estructura typedef a incompleta:

typedef struct t t1;
typedef struct t { int m; } t1; //OK

Posible caso de uso de un typedef incompleto de la matriz podría ser algo como esto:

int main(int n, char **pp)
{
typedef int t1[][200];
typedef struct t { t1 *m; int m1; } t0;
typedef int t1[sizeof (t0)][200];
}

En el ejemplo anterior me gustaría declarar unapuntero a matriz dentro de una estructura con número de elementos igual al tamaño de la estructura. Sí, podría usar una estructura en lugar de una matriz, pero ¿por qué debería hacerlo cuando la opción anterior está potencialmente disponible?

Respuestas

4 para la respuesta № 1

typedef int t[2]; no está permitido debido a la restricción 6.7 / 3:

Si un identificador no tiene enlace, no habrá más de una declaración del identificador (en un declarador o especificador de tipo) con el mismo alcance y en el mismo espacio de nombre, excepto que:

  • un nombre typedef puede ser redefinido para denotar el mismo tipo como lo hace actualmente, siempre que el tipo no sea un tipo modificado de forma variable;

sin embargo int[] y int[2] no son del mismo tipo, por lo que este "excepto" no se aplica, por lo que el código viola la restricción.


Respecto a tu primera cita: Aunque 6.2.22/2 dice que se puede completar un tipo incompleto, no se tiene en cuenta que cualquier intento de finalización es automáticamente legal. El intento de finalización también debe cumplir con todas las otras reglas del idioma, y ​​en este caso no cumple con 6.7 / 3.

los int a[]; int a[2]; El ejemplo está bien (bajo 6.7 / 3) porque a tiene vinculación; y en el typedef struct t t1; , struct t sigue siendo el mismo tipo antes y después de su finalización.


0 para la respuesta № 2

De 6.2.5p1, podemos ver una definición de los términos completar y incompleto:

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 (tener información suficiente).

Así, cuando hablamos de un tipo Al estar incompleto, realmente estamos hablando del tamaño de objetos de ese tipo siendo indeterminado. No podemos hablar de "tipos incompletos" sin declarar un objeto de ese tipo.

En tu primer ejemplo, el tamaño de a Está determinado como has completado la definición para el objeto Utilizando la segunda declaración.

En tu segundo ejemplo, ninguna declaración. para un objeto está hecho. Una vez que se hace la declaración, por ej. t x = { 1, 2 };, queda claro que el tipo no es incompleto.

En su tercer ejemplo, no está completando realmente el alias de tipo; está completando el struct definición. También podrías haber escrito:

typedef struct t t1;
struct t { int m; };

Podemos ver más apoyo para la redefinición de struct etiquetas, y la exclusión de la redefinición VLA en 6.7p3:

Si un identificador no tiene enlace, no habrá más de una declaración del identificador (en un declarador o especificador de tipo) con el mismo alcance y en el mismo espacio de nombre, excepto que:

  • un nombre typedef puede ser redefinido para denotar el mismo tipo como lo hace actualmente, siempre que el tipo no sea un tipo modificado de forma variable;
  • las etiquetas pueden ser redeclaradas como se especifica en 6.7.2.3.