2012-10-12 359 views
7

¿Por qué el concepto de relleno se agrega solo cuando hay varios miembros de una estructura y por qué no se incluye cuando hay un único miembro de tipo de datos básico?¿Por qué se agrega el relleno para los miembros de datos múltiples de estructuras y no para miembros individuales?

si tenemos en cuenta en una máquina de 32 bits

struct 
{ 
    char a; 
} Y; 

no tiene ningún relleno y sizeof Y viene a 1 byte.

Si tenemos en cuenta esta estructura

struct 
{ 
    char a; 
    int b; 
} X; 

Sizeof X será 8 bytes.

Mi pregunta es ¿Por qué agregar relleno en el segundo caso? Si se trata de un acceso eficiente de la máquina que normalmente lee datos en bloques de múltiplos de 4 bytes, ¿por qué no hubo relleno en el primer caso?

Respuesta

10

El relleno se agrega en el segundo caso porque, en su máquina, un int está alineado a 4 bytes. Así que tiene que residir en una dirección que es divisible a 4.

0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 

    a  b  b  b  b  

Si no se añade el relleno, el miembro int comienza en la dirección 0x05, lo cual es incorrecto. Con 3 añadido bytes de relleno:

0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 

    a |  padding  | b  b  b  b 

Ahora el int está en 0x08, lo cual está bien.

+0

I <3 ASCII ART! –

+0

Hola, ¿qué tal el caso struct {int b; char a; } X; Aquí si consideramos que int comienza desde la ubicación de la memoria en múltiplo de 4 y char para stat más tarde. El relleno también se realiza en este caso. ¿Por qué se requiere un relleno aquí si todos los miembros de la información siguen las condiciones de contorno? – Laavaa

+1

@AbhishekSrinath debido a las matrices. Si tiene 'X x [2]', el segundo elemento - 'x [1]' - debe estar alineado a 4 bytes porque su primer miembro es 'int', que debe estar alineado a 4 bytes. –

3

No es solo eficiencia.

El problema no es el tamaño del acceso per se, sino su alineación. En mayoría de las máquinas, el acceso a datos desalineados hará que el programa de accidente, y en las máquinas típicas de hoy, un int requerirá una dirección alineados en un límite de cuatro bytes: acceder a un int cuya dirección no es alineados en un límite de cuatro bytes ralentizará considerablemente el programa o hará que se bloquee. Su primera estructura no contenía ningún dato con consideraciones de alineación, por lo que no era necesario ningún relleno. Su segundo tiene un int, y el compilador tiene que asegurarse de que, dado un conjunto de , todos los int estarán alineados correctamente. Esto significa que 1) el tamaño total de la estructura debe ser un múltiplo de cuatro, y 2) el desplazamiento del int en la estructura debe ser un múltiplo de cuatro. (Considerando el primer requisito:

struct S 
{ 
    char a; 
    int b; 
    char c; 
}; 

tendrá generalmente un tamaño de 12, con el acolchado después de que ambos char.)

En otras langauges, era frecuente para el compilador para reordenar estructuras de modo que los elementos con los requisitos de alineación estrictas llegaron primera — para struct S, anteriormente, esto habría dado lugar a:

struct S 
{ 
    int b; 
    char a; 
    char c; 
}; 

y un tamaño de 8, en lugar de 12. Sin embargo, tanto C como C++ lo prohíben.

+0

Hola, entonces ¿qué tal el caso struct {int b; char a; } X; Aquí si consideramos que int comienza desde la ubicación de la memoria en múltiplo de 4 y char para stat más tarde. El relleno también se realiza en este caso. ¿Por qué se requiere un relleno aquí si todos los miembros de la información siguen las condiciones de contorno? – Laavaa

+0

@AbhishekSrinath para que el siguiente miembro de una matriz se alinee correctamente. –

0

El relleno se realiza para alinear ciertos tipos de datos, es decir, para asegurar que los datos de un tipo determinado tengan una dirección que sea un múltiplo de un número especificado. Esto varía entre los diferentes modelos de CPU, pero a menudo los enteros de 2 bytes se alinean con direcciones que son múltiplos de enteros de 2 y 4 bytes para direcciones que son múltiplos de 4. Normalmente, los caracteres no necesitan alinearse.

De modo que si solo hay un campo en una estructura, siempre que la estructura se coloque en una dirección con el límite adecuado, no hay necesidad de relleno. Y siempre lo será: el sistema siempre alinea los bloques con el límite más grande que alguna vez se requerirá, generalmente 4 bytes u 8 bytes. La única cosa en la estructura será en un límite apropiado. El problema solo aparece cuando tiene varios campos, ya que la longitud de un campo puede no dar como resultado que el siguiente campo esté en el límite apropiado. Entonces, en su ejemplo, tiene una char, que por supuesto toma 1 byte, y una int, que toma 4. Supongamos que la estructura se coloca en la dirección 0x1000. Luego, sin relleno, el carácter se colocará en 0x1000 y el int en 0x1001. Pero los int son más eficientes cuando se encuentran en límites de 4 bytes, por lo que el compilador agrega algunos bytes de pad para llevarlo al siguiente límite, 0x1004. Entonces ahora tiene char (1 byte), relleno (3 bytes), int (4 bytes), un total de 8 bytes.

No hay mucho que pueda hacer para mejorar la situación en este caso. Cada estructura se alineará con un límite de 4 u 8 bytes, de modo que cuando el mínimo sea de 5 bytes, siempre se redondeará al menos a 8 en la práctica. (El sizeof no mostrará el relleno entre las estructuras, solo dentro, pero la memoria aún se pierde.)

En otros casos, puede minimizar el número de bytes de la libreta reorganizando el orden de los campos. Como decir que tienes tres char y tres int. Si se declara la estructura como

struct {char a; int b; char c; int d; char e; int f;} 

entonces el compilador añadirá 3 bytes después de que el primer carácter para alinear la primera int, y luego tres bytes más después de la segunda char a alinear el segundo int. Eso da char (1) + pad (3) + int (4) + char (1) + pad (3) + int (4) + char (1) + pad (3) + int (4) = 24.

Pero si por el contrario lo declaró:

struct {char a; char c; char e; int b; int d; int f;} 

entonces se obtendría char (1) + char (1) + char (1) + pad (1) + int (4) + int (4) + int (4) = 16.

Hace años leí el consejo de poner siempre los elementos más grandes primero para minimizar el relleno, es decir, primero poner longs, luego ints, luego short, y luego chars.

Si está asignando miles o millones de estos, puede guardar mucha memoria con esta técnica. Si solo va a asignar uno o dos, no va a importar mucho.

+0

Hola, entonces ¿qué tal el caso struct { int b; char a; } X; Aquí si consideramos que int comienza desde la ubicación de la memoria en múltiplo de 4 y char para stat más tarde. El relleno también se realiza en este caso. ¿Por qué se requiere un relleno aquí si todos los miembros de la información siguen las condiciones de contorno? – Laavaa

+0

@AbhishekSrinath Si hace un poco de eso, creo que obtendrá 5, no hay indicios de ningún relleno. Pero cuando creas realmente tales objetos, el montón alineará todos los objetos en el límite del peor de los casos, ya sea 4 u 8, de modo que terminarás con 3 bytes adicionales al comienzo del próximo objeto de todos modos. Puede depender de si está asignando objetos individuales del montón, objetos en la pila o matrices. Estoy bastante seguro de que el relleno es todo dependiente de la implementación, por lo que puede obtener diferentes resultados en diferentes sistemas. El punto es acomodar los requisitos de la CPU para la alineación de datos. – Jay

0

Padding es el concepto de alignment, para la issue of computer efficiency and the speed of the access of the data, los datos alineados están perfectamente acceder con el fetching cycle of the processor from the addresses where the data are stored, it doesn't mean that with out alignment processor doesn't work it only meant for the speed access of the memory, para los datos de tipo entero es 4 alineación byte se realiza por el compilador para acceder a los datos de manera más eficiente por el procesador .(en el sistema de 32 bits)

En caso de que solo se necesite un byte para los datos, no hay necesidad de alineación, ya que cada byte está disponible (in RAM there are pages and each page size is 1 byte) pero para el entero necesitamos 4 bytes y no hay 4 bytes disponibles o no hay nada que se llame acceder a 4 bytes a la vez, entonces, el compilador crea una regla de alineación según la cual los datos enteros están en las direcciones correctas.

y mediante el cual hará que la memoria tenga un acceso más rápido a los datos.

+0

¿Por qué colocas arbitrariamente palabras en código/pre-etiquetas? ¿Olvidaste nombrar tus fuentes? –

Cuestiones relacionadas