Uso sizeof para obtener el tamaño de una estructura en C, pero el resultado que obtuve es inesperado.
struct sdshdr { int len; int free; char buf[]; }; int main(){ printf("struct len:%d\n",(sizeof(struct sdshdr))); return 0; } //struct len:8, with or without buf
mi pregunta es ¿por qué buf
no ocupa ningún espacio y por qué el tamaño del tipo int
sigue siendo 4 en una CPU de 64 bits?
aquí está la salida de gcc -v
:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) Target: x86_64-apple-darwin14.4.0 Thread model: posix
El [] es un miembro de matriz flexible . No cuentan para el tamaño total de la estructura, porque el estándar C lo dice explícitamente:
6.7.2.1/18
Como caso especial, el último elemento de una estructura con más de un miembro con nombre puede tener un tipo de matriz incompleta; esto se denomina miembro de matriz flexible. En la mayoría de las situaciones, se ignora el miembro de matriz flexible. En particular, el tamaño de la estructura es como si se hubiera omitido el miembro de matriz flexible, excepto que puede tener más relleno final de lo que implicaría la omisión.
Esto es intencional por diseño, porque el propósito de un miembro de matriz flexible es permitirle asignar datos finales de forma dinámica después de la estructura. (Cuando la estructura es un encabezado de archivo, encabezado de protocolo, etc.)
Ejemplo que incluye una discusión sobre las extensiones gcc no estándar y el antiguo "truco de estructura" anterior a C99.
Desde C99 en adelante, se puede omitir el tamaño de una matriz al final de una estructura. A los efectos de sizeof(struct)
, esta matriz parecerá tener un tamaño cero (aunque su presencia puede agregar algo de relleno a la estructura), pero la intención es que su longitud sea flexible , es decir, al asignar espacio para la estructura, se debe asignar la cantidad deseada de espacio adicional para la matriz al final. (Para evitar salirse de los límites, la longitud real asignada de la matriz debe almacenarse en algún lugar).
Antes de C99, era un truco bastante común tener una matriz de tamaño 1 (o 0 donde lo permitiera el compilador) al final de una estructura y luego asignarle más espacio, por lo que C99 permitió explícitamente esta práctica mediante la introducción de la matriz flexible. miembro sin tamaño dado.
Como una extensión GNU c, tiene matrices de longitud cero:
Como extensión de GNU, el número de elementos puede ser tan pequeño como cero. Las matrices de longitud cero son útiles como último elemento de una estructura que en realidad es un encabezado para un objeto de longitud variable:
por ejemplo, considere este código de The gnu c manual
struct line { int length; char contents[0]; }; { struct line *this_line = (struct line *) malloc (sizeof (struct line) + this_length); this_line -> length = this_length; }
En ISO C99, usaría un miembro de matriz flexible, que es ligeramente diferente en sintaxis y semántica:
Los miembros de la matriz flexible se escriben como contenidos[] sin el 0.
Los miembros de la matriz flexible tienen un tipo incompleto, por lo que es posible que no se aplique el operador sizeof. Como una peculiaridad de la implementación original de matrices de longitud cero, sizeof se evalúa como cero.
Los miembros de matriz flexible solo pueden aparecer como el último miembro de una estructura que, de lo contrario, no estaría vacía.
Una estructura que contiene un miembro de matriz flexible, o una unión que contiene dicha estructura (posiblemente recursivamente), no puede ser miembro de una estructura o elemento de una matriz. (Sin embargo, GCC permite estos usos como extensiones).