¿Por qué no sizeof para una estructura igual a la suma del tamaño de cada uno de los miembros?

StackOverflow https://stackoverflow.com/questions/119123

Pregunta

¿Por qué el sizeof operador de retorno de un tamaño más grande para una estructura que los tamaños totales de la estructura de los miembros?

¿Fue útil?

Solución

Esto es debido a que de relleno añadido para satisfacer la alineación de las restricciones. Estructura de datos de alineación impactos tanto en el rendimiento y corrección de los programas:

  • Alineado mal, el acceso puede ser un error de disco duro (a menudo SIGBUS).
  • Alineado mal, el acceso puede ser un error de software.
    • Ya sea corregido en el hardware, para un desempeño modesto-degradación.
    • O corregido por la emulación de software, para un rendimiento grave degradación.
    • Además, la atomicidad y otros concurrencia de garantías puede ser roto, que conduce a errores sutiles.

He aquí un ejemplo de uso de la configuración típica para un procesador x86 (todo usado de 32 y 64 bits modos):

struct X
{
    short s; /* 2 bytes */
             /* 2 padding bytes */
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

Uno puede minimizar el tamaño de las estructuras por la clasificación de los miembros de la alineación (clasificación por tamaño suficiente para que en tipos básicos) (como la estructura Z en el ejemplo de arriba).

NOTA IMPORTANTE:Tanto el C y C++ normas del estado que la estructura de la alineación de la implementación definido.Por lo tanto, cada compilador puede elegir la alineación de datos de manera diferente, lo que resulta en diferentes e incompatibles diseños de datos.Por esta razón, cuando se trata de bibliotecas que serán utilizados por los distintos compiladores, es importante entender cómo los compiladores de la alineación de datos.Algunos compiladores han de línea de comandos de configuración y/o especiales #pragma instrucciones para cambiar la estructura de la configuración de alineación.

Otros consejos

El embalaje y el byte de alineación, como se describe en la C, preguntas frecuentes aquí:

Es para la alineación.Muchos procesadores no pueden acceder a las 2 y 4 bytes cantidades (por ejemplo,int y long int) si están hacinados en todos los-que-manera.

Supongamos que tiene esta estructura:

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};

Ahora, usted puede pensar que debería ser posible para el pack esta estructura en la memoria como este:

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+

Pero es mucho, mucho más fácil en el procesador, si el compilador organiza es como este:

+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+

En el abarrotado versión, la cuenta de cómo es, al menos, un poco difícil de a usted y a mí para ver cómo la b y la c campos de envoltura alrededor?En pocas palabras, es difícil para el procesador, también.Por lo tanto, la mayoría de los compiladores de la almohadilla la estructura (como si con extra, los campos invisibles) como este:

+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+

Si desea que la estructura para tener un cierto tamaño con GCC, por ejemplo, usar __attribute__((packed)).

En Windows, puede establecer la alineación a un byte cuando se utiliza el cl.exe compier con el /Zp opción.

Generalmente es más fácil para que la CPU los datos de acceso que es un múltiplo de 4 (u 8), en función de la plataforma y también en el compilador.

Así que es cuestión de alineación básicamente.

Usted necesita tener buenas razones para cambiarlo.

Esto puede ser debido a byte alineación y relleno de modo que la estructura llega a un número par de bytes (o palabras) en su plataforma.Por ejemplo, en C en Linux, los 3 siguientes estructuras:

#include "stdio.h"


struct oneInt {
  int x;
};

struct twoInts {
  int x;
  int y;
};

struct someBits {
  int x:2;
  int y:6;
};


int main (int argc, char** argv) {
  printf("oneInt=%zu\n",sizeof(struct oneInt));
  printf("twoInts=%zu\n",sizeof(struct twoInts));
  printf("someBits=%zu\n",sizeof(struct someBits));
  return 0;
}

Tienen los miembros de que el tamaño (en bytes) de 4 bytes (32 bits), 8 bytes (2x 32 bits) y 1 byte (2+6 bits), respectivamente.El programa anterior (en Linux usando gcc) imprime los tamaños de 4, 8, y 4 - donde la última estructura es acolchada por lo que es una sola palabra (4 x 8 bytes en mi plataforma de 32 bits).

oneInt=4
twoInts=8
someBits=4

Vea también:

para Microsoft Visual C:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

y GCC reclamación de compatibilidad con Microsoft compilador.:

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

Además de las anteriores respuestas, por favor tenga en cuenta que independientemente de que el embalaje, no hay miembros de la orden-garantía en C++.Los compiladores pueden (y ciertamente lo es) agregar virtual puntero a la tabla y la base de las estructuras de los miembros de la estructura.Incluso la existencia de la tabla virtual no está garantizado por la norma (virtual mecanismo de ejecución no se especifica) y por lo tanto se puede concluir que dicha garantía es simplemente imposible.

Estoy bastante seguro de miembro de la orden es garantizado en C, pero no cuento con ello, al escribir una plataforma cruzada o cross-compiler programa.

El tamaño de una estructura es mayor que la suma de sus partes, porque de lo que se llama el embalaje.Un procesador concreto ha preferido el tamaño de los datos que funciona con.La mayoría de los procesadores modernos' tamaño preferido si de 32 bits (4 bytes).Acceso a la memoria cuando los datos es en este tipo de límite es más eficiente que las cosas que se encuentran a caballo que el límite de tamaño.

Por ejemplo.Considerar la estructura simple:

struct myStruct
{
   int a;
   char b;
   int c;
} data;

Si la máquina es un equipo de 32 bits y los datos se alinea en un límite de 32 bits, vemos un problema inmediato (suponiendo que no hay estructura de la alineación).En este ejemplo, vamos a suponer que la estructura de datos se inicia en la dirección 1024 (0x400 - tenga en cuenta que el menor de 2 bits son cero, por lo que los datos se alinea en un límite de 32 bits).El acceso a los datos.un funcionará bien, ya que comienza en la frontera - 0x400.El acceso a los datos.b va a funcionar, porque es en la dirección 0x404 - otro límite de 32 bits.Pero sin alinear la estructura de datos.c en la dirección 0x405.Los 4 bytes de datos.c están en 0x405, 0x406, 0x407, 0x408.En un equipo de 32 bits, el sistema de lectura de datos.c durante un ciclo de memoria, pero sólo se consigue con 3 de los 4 bytes (el 4to byte es el siguiente límite).Así, el sistema tendría que hacer un segundo acceso a memoria para obtener el 4to byte,

Ahora, si en lugar de poner los datos.c en la dirección 0x405, el compilador collar de la estructura por 3 bytes y poner los datos.c en la dirección 0x408, a continuación, el sistema sólo se necesita 1 ciclo para leer los datos, el corte de tiempo de acceso a los elementos de datos en un 50%.El relleno de los swaps de eficiencia de memoria para el procesamiento de la eficiencia.Dado que las computadoras pueden tener enormes cantidades de memoria (muchos gigabytes), los compiladores sentir que el swap (velocidad sobre el tamaño) es razonable.

Por desgracia, este problema se convierte en un asesino cuando intenta enviar las estructuras a través de una red o incluso escribir los datos binarios a un archivo binario.El relleno se inserta entre los elementos de una estructura o clase pueden alterar los datos que se envían al archivo o a la red.Para escribir el código portable (uno que va a ir a diferentes compiladores), usted probablemente tendrá que acceder a cada elemento de la estructura por separado para garantizar la correcta "embalaje".

Por otro lado, compiladores diferentes tienen diferentes capacidades para la gestión de la estructura de datos de embalaje.Por ejemplo, en Visual C/C++ el compilador soporta el #pragma pack de comandos.Esto le permitirá ajustar los datos de embalaje y la alineación.

Por ejemplo:

#pragma pack 1
struct MyStruct
{
    int a;
    char b;
    int c;
    short d;
} myData;

I = sizeof(myData);

Yo ahora debe tener la longitud de 11.Sin el pragma, podría ser cualquier cosa, desde los 11 a 14 años (y para algunos sistemas, como mucho 32), dependiendo del defecto de embalaje del compilador.

Puede hacerlo si tiene implícita o explícitamente establece la alineación de la estructura.Una estructura que está alineado 4 siempre será un múltiplo de 4 bytes, incluso si el tamaño de sus miembros sería algo que no es un múltiplo de 4 bytes.

También una biblioteca puede ser compilado bajo x86 de 32 bits enteros y puede ser la comparación de sus componentes en un proceso de 64 bits iba a dar un resultado diferente si estaban haciendo con la mano.

C99 N1256 borrador de estándar

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4 El operador sizeof:

3 Cuando se aplica a un operando que tiene la estructura o tipo de unión, el resultado es el número total de bytes de un objeto,se incluyendo interna y posterior relleno.

6.7.2.1 de la Estructura y de la unión de los especificadores de:

13 ...No puede ser sin nombre relleno dentro de una estructura de objetos, pero no en su principio.

y:

15 No puede ser identificado de relleno en el extremo de una estructura o de la unión.

El nuevo C99 flexible miembro de la matriz característica (struct S {int is[];};) también puede afectar el relleno:

16 Como un caso especial, el último elemento de una estructura con más de una nombrado miembro de mayo han incompleta del tipo de matriz;esto se llama una flexible miembro de la matriz.En la mayoría de las situaciones, el flexible miembro de la matriz es ignorado.En particular, el tamaño de la estructura es como si el flexible miembro de la matriz se omite la excepción de que puede haber más tirados relleno de la omisión implicaría.

Anexo J Problemas De Portabilidad reitera:

Los siguientes son no especificado:...

  • El valor de los bytes de relleno al almacenar los valores en las estructuras o los sindicatos (6.2.6.1)

C++11 N3337 borrador de estándar

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3 Sizeof:

2 Cuando se aplica para una clase, el resultado es el número de bytes en un objeto de esa clase, incluyendo cualquier relleno necesario para la colocación de los objetos de ese tipo en una matriz.

9.2 los miembros de la Clase:

Un puntero a un estándar de diseño de estructura de objetos, convenientemente convertido usando un reinterpret_cast, puntos a su miembro inicial (o si el miembro es un poco de campo, luego a la unidad en la que reside) y viceversa.[ Nota:Por tanto, podría sin nombre relleno dentro de los estándares de diseño de la estructura del objeto, pero no en su inicio, como sea necesario para lograr una adecuada alineación.— nota final ]

Sólo sé lo suficiente como C++ para entender la nota :-)

En adición a las otras respuestas, una estructura que puede (pero usualmente no) tienen funciones virtuales, en cuyo caso el tamaño de la estructura también incluye el espacio para la vtbl.

C lenguaje de hojas compilador de cierta libertad acerca de la ubicación de los elementos estructurales en la memoria:

  • la memoria de los agujeros pueden aparecer entre los dos componentes, y después de que el último componente.Fue debido al hecho de que ciertos tipos de objetos en el equipo de destino puede estar limitado por los límites de abordar
  • "la memoria "agujeros" tamaño incluido en el resultado de operador sizeof.La sizeof sólo no incluyen el tamaño de la matriz flexible, que está disponible en C/C++
  • Algunas implementaciones del lenguaje permiten el control de la memoria de diseño de estructuras a través de la pragma y opciones del compilador

El lenguaje C proporciona algún tipo de garantía para el programador de la disposición de los elementos en la estructura:

  • los compiladores necesarios para asignar una secuencia de componentes el aumento de las direcciones de memoria
  • La dirección de la primera componente coincide con la dirección de inicio de la estructura
  • sin nombre los campos de bits pueden ser incluidos en la estructura de la dirección necesaria alineaciones de los elementos adyacentes

Problemas relacionados con los elementos de la alineación:

  • Diferentes equipos de la línea de los bordes de los objetos de diferentes maneras
  • Diferentes restricciones en el ancho del campo de bits
  • Los equipos difieren sobre cómo almacenar los bytes de una palabra (Intel 80x86 y Motorola 68000)

Cómo alineación de las obras:

  • El volumen ocupado por la estructura se calcula como el tamaño de la alineados único elemento de una matriz de este tipo de estructuras.La estructura debe final, de manera que el primer elemento de la siguiente estructura no las violen los requisitos de alineación

p.s información Más detallada están disponibles aquí:"Samuel P. Harbison, Guy L. Steele C De Referencia, (5.6.2 - 5.6.7)"

La idea es que para la velocidad y la memoria caché de las consideraciones de los operandos debe ser leído desde direcciones alineado a su tamaño natural.Para que esto suceda, el compilador de las almohadillas de los miembros de la estructura por lo que el siguiente miembro o siguiente estructura va a estar alineadas.

struct pixel {
    unsigned char red;   // 0
    unsigned char green; // 1
    unsigned int alpha;  // 4 (gotta skip to an aligned offset)
    unsigned char blue;  // 8 (then skip 9 10 11)
};

// next offset: 12

La arquitectura x86 siempre ha sido capaz de recuperar desalineados direcciones.Sin embargo, es más lento y cuando la desalineación se superpone dos diferentes líneas de caché, entonces se le desaloja dos líneas de caché cuando un alineados acceso, sólo desalojar a uno.

Algunas arquitecturas en realidad la trampa en la desalineados lee y escribe, y las primeras versiones de la arquitectura ARM (la que ha evolucionado en todos los móviles de hoy en día Cpu) ...bueno, en realidad, acaba de regresar a los malos datos sobre aquellos.(Se omiten los bits de orden.)

Por último, tenga en cuenta que las líneas de caché puede ser arbitrariamente grande, y el compilador no intentar adivinar o hacer un espacio-vs-la velocidad de equilibrio.En su lugar, la alineación de las decisiones son parte de la ABI y representan el mínimo de alineación que eventualmente uniformemente llenar una línea de caché.

TL;DR: la alineación es importante.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top