Considerar:
struct mystruct_A
{
char a;
int b;
char c;
} x;
struct mystruct_B
{
int b;
char a;
} y;
Los tamaños de las estructuras son 12 y 8 respectivamente.
¿Estas estructuras están acolchadas o empaquetadas?
¿Cuándo se realiza el relleno o el embalaje?
padding
hace las cosas más grandespacking
hace las cosas más pequeñas Totalmente diferente.Respuestas:
El relleno alinea a los miembros de la estructura con los límites de direcciones "naturales"; por ejemplo, los
int
miembros tendrían compensaciones, que estánmod(4) == 0
en la plataforma de 32 bits. El relleno está activado de forma predeterminada. Inserta los siguientes "vacíos" en su primera estructura:El embalaje , por otro lado, evita que el compilador realice relleno (esto debe solicitarse explícitamente) en GCC
__attribute__((__packed__))
, por lo que es lo siguiente:produciría estructura de tamaño
6
en una arquitectura de 32 bits.Sin embargo, una nota: el acceso a la memoria no alineado es más lento en las arquitecturas que lo permiten (como x86 y amd64), y está explícitamente prohibido en arquitecturas de alineación estrictas como SPARC.
fuente
( Las respuestas anteriores explicaron el motivo con bastante claridad, pero no parece del todo claro sobre el tamaño del relleno, por lo tanto, agregaré una respuesta de acuerdo con lo que aprendí de The Lost Art of Structure Packing , ha evolucionado para no limitarse
C
, pero también es aplicable aGo
,Rust
. )Alinear memoria (para estructura)
Reglas:
por ejemplo, en un sistema de 64 bits,
int
debe comenzar en la dirección divisible por 4, ylong
por 8,short
por 2.char
ychar[]
son especiales, podrían ser cualquier dirección de memoria, por lo que no necesitan relleno antes de ellos.struct
, además de la necesidad de alineación para cada miembro individual, el tamaño de la estructura completa en sí se alineará con un tamaño divisible por el tamaño del miembro individual más grande, mediante relleno al final.por ejemplo, si el miembro más grande de struct es
long
divisible por 8,int
luego por 4 yshort
luego por 2.Orden de miembro:
stu_c
ystu_d
del ejemplo a continuación tienen los mismos miembros, pero en diferente orden, y resultan en un tamaño diferente para las 2 estructuras.Dirección en memoria (para estructura)
Reglas:
La dirección de estructura del sistema de 64 bits comienza desde
(n * 16)
bytes. ( Puede ver en el siguiente ejemplo, todas las direcciones hexadecimales impresas de las estructuras terminan con0
) .Motivo : el miembro de estructura individual más grande posible es 16 bytes (
long double
).char
como miembro, su dirección podría comenzar en cualquier dirección.Espacio vacio :
ejemplo, a
test_struct_address()
continuación, la variablex
reside entre la estructura adyacenteg
yh
.No importa si
x
se declara,h
la dirección no cambiará,x
solo reutilizará el espacio vacío que seg
desperdició.Caso similar para
y
.Ejemplo
( para sistema de 64 bits )
memory_align.c :
Resultado de ejecución -
test_struct_padding()
:Resultado de ejecución -
test_struct_address()
:Por lo tanto, el inicio de la dirección para cada variable es g: d0 x: dc h: e0 y: e8
fuente
<The Lost Art of C Structure Packing>
explica bastante bien las reglas, incluso aunque es un poco más largo que esta respuesta. El libro está disponible gratuitamente en línea: catb.org/esr/structure-packingSé que esta pregunta es antigua y la mayoría de las respuestas aquí explican muy bien el relleno, pero al tratar de comprenderlo, pensé que ayudaría tener una imagen "visual" de lo que estaba sucediendo.
El procesador lee la memoria en "fragmentos" de un tamaño definido (palabra). Digamos que la palabra del procesador tiene 8 bytes de longitud. Verá la memoria como una gran fila de bloques de construcción de 8 bytes. Cada vez que necesite obtener información de la memoria, alcanzará uno de esos bloques y la obtendrá.
Como parece en la imagen de arriba, no importa dónde esté un Char (1 byte de largo), ya que estará dentro de uno de esos bloques, lo que requiere que la CPU procese solo 1 palabra.
Cuando manejamos datos de más de un byte, como un byte int de 4 byte o un doble de 8 byte, la forma en que se alinean en la memoria hace una diferencia en cuántas palabras tendrá que procesar la CPU. Si los fragmentos de 4 bytes están alineados de manera que siempre quepan en el interior de un bloque (la dirección de memoria es un múltiplo de 4), solo se tendrá que procesar una palabra. De lo contrario, un trozo de 4 bytes podría tener parte de sí mismo en un bloque y parte en otro, requiriendo que el procesador procese 2 palabras para leer estos datos.
Lo mismo se aplica a un doble de 8 bytes, excepto que ahora debe estar en una dirección de memoria múltiplo de 8 para garantizar que siempre estará dentro de un bloque.
Esto considera un procesador de texto de 8 bytes, pero el concepto se aplica a otros tamaños de palabras.
El relleno funciona rellenando los espacios entre esos datos para asegurarse de que estén alineados con esos bloques, mejorando así el rendimiento al leer la memoria.
Sin embargo, como se indica en otras respuestas, a veces el espacio es más importante que el rendimiento en sí mismo. Tal vez esté procesando muchos datos en una computadora que no tiene mucha RAM (se podría usar el espacio de intercambio, pero es MUCHO más lento). Puede organizar las variables en el programa hasta que se complete el menor relleno (como se ejemplificó en otras respuestas) pero si eso no es suficiente, puede desactivar explícitamente el relleno, que es lo que es el empaque .
fuente
El relleno de estructura suprime el relleno de estructura, el relleno utilizado cuando la alineación es más importante, el relleno utilizado cuando el espacio es más importante.
Algunos compiladores proporcionan
#pragma
suprimir el relleno o empaquetarlo en n número de bytes. Algunos proporcionan palabras clave para hacer esto. Generalmente, el pragma que se usa para modificar el relleno de la estructura estará en el formato siguiente (depende del compilador):Por ejemplo, ARM proporciona la
__packed
palabra clave para suprimir el relleno de estructura. Consulte el manual del compilador para obtener más información al respecto.Por lo tanto, una estructura compacta es una estructura sin relleno.
Generalmente se utilizarán estructuras empaquetadas
para ahorrar espacio
para formatear una estructura de datos para transmitir a través de la red utilizando algún protocolo (esta no es una buena práctica, por supuesto, porque necesita
lidiar con la resistencia)
fuente
El relleno y el embalaje son solo dos aspectos de la misma cosa:
En
mystruct_A
, suponiendo una alineación predeterminada de 4, cada miembro se alinea en un múltiplo de 4 bytes. Como el tamaño dechar
es 1, el relleno paraa
yc
es 4 - 1 = 3 bytes, mientras que no se requiere relleno para elint b
que ya es de 4 bytes. Funciona de la misma manera paramystruct_B
.fuente
El empaquetamiento de estructura solo se realiza cuando le indica a su compilador explícitamente que empaquete la estructura. El relleno es lo que estás viendo. Su sistema de 32 bits está rellenando cada campo para la alineación de palabras. Si le hubiera dicho a su compilador que empaquetara las estructuras, serían 6 y 5 bytes, respectivamente. Aunque no hagas eso. No es portátil y hace que los compiladores generen código mucho más lento (y a veces incluso con errores).
fuente
¡No hay peros al respecto! Quien quiera comprender el tema debe hacer lo siguiente:
fuente
Reglas para el relleno:
Por qué Regla 2: Considere la siguiente estructura,
Si tuviéramos que crear una matriz (de 2 estructuras) de esta estructura, no se requerirá relleno al final:
Por lo tanto, el tamaño de struct = 8 bytes
Supongamos que creamos otra estructura de la siguiente manera:
Si tuviéramos que crear una matriz de esta estructura, hay 2 posibilidades, de la cantidad de bytes de relleno necesarios al final.
A. Si agregamos 3 bytes al final y lo alineamos para int y no Long:
B. Si agregamos 7 bytes al final y lo alineamos para Long:
La dirección de inicio de la segunda matriz es un múltiplo de 8 (es decir, 24). El tamaño de la estructura = 24 bytes.
Por lo tanto, al alinear la dirección de inicio de la siguiente matriz de la estructura con un múltiplo del miembro más grande (es decir, si creáramos una matriz de esta estructura, la primera dirección de la segunda matriz debe comenzar en una dirección que es un múltiplo del miembro más grande de la estructura. Aquí está, 24 (3 * 8)), podemos calcular el número de bytes de relleno necesarios al final.
fuente
La alineación de la estructura de datos es la forma en que los datos se organizan y acceden en la memoria de la computadora. Consiste en dos problemas separados pero relacionados: alineación de datos y relleno de estructura de datos . Cuando una computadora moderna lee o escribe en una dirección de memoria, lo hará en fragmentos de tamaño de palabra (por ejemplo, fragmentos de 4 bytes en un sistema de 32 bits) o mayor. La alineación de datos significa colocar los datos en una dirección de memoria igual a un múltiplo del tamaño de la palabra, lo que aumenta el rendimiento del sistema debido a la forma en que la CPU maneja la memoria. Para alinear los datos, puede ser necesario insertar algunos bytes sin sentido entre el final de la última estructura de datos y el comienzo de la siguiente, que es el relleno de la estructura de datos.
fuente