Declaración de matriz sin usar en una estructura

¿Por qué C permite esto?

 typedef struct s
 {
   int arr [];
 } s;

donde la matriz arr no tiene un tamaño especificado?

Esta es la característica C99 llamada arreglos flexibles , la característica principal es permitir el uso de características de matriz de longitud variable dentro de una estructura y R .. en esta respuesta a otra pregunta sobre miembros de matriz flexibles proporciona una lista de beneficios para usar matrices flexibles sobre punteros . El borrador del estándar C99 en la sección 6.7.2.1 Estructura y especificadores de unión párrafo 16 dice:

Como un caso especial, el último elemento de una estructura con más de un miembro nombrado puede tener un tipo de matriz incompleto; esto se llama un miembro de matriz flexible. En la mayoría de las situaciones, el miembro de matriz flexible se ignora. En particular, el tamaño de la estructura es como si se hubiera omitido el miembro flexible de la matriz, excepto que puede tener más relleno posterior de lo que implicaría la omisión. […]

Por lo tanto, si tuviera una s* asignaría espacio para la matriz además del espacio requerido para la estructura , generalmente tendría otros miembros en la estructura:

 s *s1 = malloc( sizeof(struct s) + n*sizeof(int) ) ; 

el proyecto de norma en realidad tiene un ejemplo instructivo en el párrafo 17 :

EJEMPLO Después de la statement:

  struct s { int n; double d[]; }; 

la estructura struct s tiene un miembro de matriz flexible d . Una forma típica de usar esto es:

  int m = /* some value */; struct s *p = malloc(sizeof (struct s) + sizeof (double [m])); 

y suponiendo que la llamada a malloc tiene éxito, el objeto apuntado por p comporta, para la mayoría de los propósitos, como si p hubiera sido declarado como:

  struct { int n; double d[m]; } *p; 

(hay circunstancias en las que esta equivalencia se rompe, en particular, las compensaciones del miembro d pueden no ser las mismas).

Probablemente esté buscando matrices flexibles en C99. Los miembros de matriz flexible son miembros de tamaño desconocido al final de una estructura / unión.

Como un caso especial, el último elemento de una estructura con más de un miembro nombrado puede tener un tipo de matriz incompleto; esto se llama un miembro de matriz flexible. En la mayoría de las situaciones, el miembro de matriz flexible se ignora. En particular, el tamaño de la estructura es como si se hubiera omitido el miembro flexible de la matriz, excepto que puede tener más relleno posterior de lo que implicaría la omisión.

También puede ver la razón del hack de estructura en primer lugar.

No está claro si es legal o portátil, pero es bastante popular. Una implementación de la técnica podría verse más o menos así:

  #include  #include  struct name *makename(char *newname) { struct name *ret = malloc(sizeof(struct name)-1 + strlen(newname)+1); /* -1 for initial [1]; +1 for \0 */ if(ret != NULL) { ret->namelen = strlen(newname); strcpy(ret->namestr, newname); } return ret; } 

Esta función asigna una instancia de la estructura de nombre con el tamaño ajustado para que el campo de nombre pueda contener el nombre solicitado (no solo un carácter, como sugeriría la statement de estructura).

A pesar de su popularidad, la técnica también es algo notoria: Dennis Ritchie lo ha llamado “amistad sin garantías con la implementación C”. Una interpretación oficial ha considerado que NO se ajusta estrictamente al Estándar C, aunque parece funcionar en todas las implementaciones conocidas. Los comstackdores que controlan cuidadosamente los límites de la matriz pueden emitir advertencias.