tag example description c struct

example - ¿Importa el orden de los miembros en una estructura?



alt tags (5)

He encontrado un comportamiento peculiar en C. Considere el siguiente código:

struct s { int a; }; struct z { int a; struct s b[]; }; int main(void) { return 0; }

Compila muy bien. A continuación, cambie el orden de los miembros de struct z como tal

struct z { struct s b[]; int a; };

Y, de repente, obtenemos que el field has incomplete type ''struct s []'' error de compilación field has incomplete type ''struct s []'' .

¿Porqué es eso?


El compilador no puede calcular la cantidad de memoria struct sb[]; consumirá Esto significa que si la estructura tiene campos posteriores, el compilador no puede determinar dónde están esos campos.

Solía ​​ser (en versiones antiguas de C) que (por ejemplo) struct sb[]; no se permitió como miembro de una estructura. Esto hizo que la administración eficiente de la memoria sea molesta. Para un ejemplo simple, imagina que tienes una estructura que contiene una cadena de "nombre" (que podrían ser solo unos pocos caracteres o muchos de ellos). Podría usar una matriz de tamaño fijo que sea lo suficientemente grande para el nombre más grande (que desperdicia espacio), o use un puntero y asigne 2 pedazos de memoria (uno para la estructura y otro para la cadena de nombre de longitud variable). Alternativamente, puede usar un puntero y hacer que apunte a un espacio extra más allá del final de la estructura, que termina algo como esto:

length = strlen(my_string); foo = malloc(sizeof(MYSTRUCTURE) + length + 1); foo->name = (void *)foo + sizeof(MYSTRUCTURE); // Set pointer to extra bytes past end of structure memcpy(foo->name, my_string, length + 1);

Esta fue la opción más eficiente; pero también es feo y propenso a errores.

Para evitar esto, los compiladores agregaron extensiones no estándar para permitir "matrices de tamaño desconocido" al final de la estructura. Esto lo hizo un poco más fácil para los programadores y lo hizo un poco más eficiente (ya que no hay necesidad de un miembro de puntero adicional). Esto terminó siendo adoptado por el estándar C (tal vez en C99, no lo recuerdo).


El orden de los campos en una struct sí importa: el compilador no puede reordenar campos, por lo que el tamaño de la struct puede cambiar como resultado de agregar algo de relleno.

En este caso, sin embargo, está definiendo un llamado miembro flexible , una matriz cuyo tamaño puede cambiar. Las reglas para los miembros flexibles son

  • Es posible que nunca haya más de un miembro de ese tipo,
  • Si está presente, el miembro flexible debe ser el último en la struct , y
  • La struct debe tener al menos un miembro además del flexible.

Eche un vistazo a esta sección de Preguntas y Respuestas para una pequeña ilustración sobre el uso de miembros de estructura flexible.


El orden del miembro generalmente es importante (es decir, se puede insertar algo de relleno entre los campos) pero en su caso específico está utilizando una matriz de miembros flexibles , esto está estandarizado en C99 - 6.7.2.1.16

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.

Su struct sb[]; miembro está destinado a ser utilizado para acceder a las asignaciones dinámicas de montón para struct s elementos de múltiples struct s .


El título de su pregunta es "¿Importa el orden de los miembros en una struct ?".

El problema obvio en su código se relaciona con el hecho de que su struct contiene un miembro flexible.

Entonces aquí hay un problema adicional relacionado con la pregunta general del orden de los miembros en una struct :

Tome las dos estructuras siguientes, por ejemplo:

struct s1 { int a; short b; char c; }; struct s2 { char c; short b; int a; };

La mayoría de los compiladores agregarán relleno para alinear cada miembro a una dirección divisible por su tamaño.

Entonces struct s2 puede finalmente compilar en:

struct s2 { char c; char pad1; short b; short pad2; short pad3; int a; };

Esto eventualmente dará como resultado diferentes tamaños para instancias de tipos struct s1 y struct s2 .


La orden sí importa EN ESTE CASO. Su struct z contiene una matriz compuesta de structs s . Sin embargo, esta matriz no tiene un tamaño asociado, por lo que el compilador no sabe cómo asignar el espacio de pila apropiado, ya que hay otro campo de la estructura ( int a ) después. Un ejemplo de cómo funcionaría:

struct s { int a; } struct z { struct s b[10]; int a; } int main(void) { return 0; }

Si realmente necesita que la matriz cambie de tamaño, es mejor si asigna la estructura completa en el montón con la matriz como un puntero a struct s y luego la reasigna dinámicamente para acomodar el cambiante tamaño de la matriz. Busque malloc (3) , realloc 3) , calloc (3) y free (3) .