
cenoc
Me preguntaba si alguien podría explicarme qué es lo que #pragma pack
la declaración del preprocesador lo hace y, lo que es más importante, por qué uno querría usarlo.
Revisé el página MSDN, que ofreció una idea, pero esperaba escuchar más de personas con experiencia. Lo he visto en código antes, aunque parece que ya no puedo encontrar dónde.

nick meyer
#pragma pack
indica al compilador que empaquete los miembros de la estructura con una alineación particular. La mayoría de los compiladores, cuando declara una estructura, insertarán relleno entre los miembros para garantizar que estén alineados con las direcciones adecuadas en la memoria (generalmente un múltiplo del tamaño del tipo). Esto evita la penalización de rendimiento (o el error total) en algunas arquitecturas asociadas con el acceso a variables que no están alineadas correctamente. Por ejemplo, dados enteros de 4 bytes y la siguiente estructura:
struct Test
{
char AA;
int BB;
char CC;
};
El compilador podría optar por colocar la estructura en la memoria de esta manera:
| 1 | 2 | 3 | 4 |
| AA(1) | pad.................. |
| BB(1) | BB(2) | BB(3) | BB(4) |
| CC(1) | pad.................. |
y sizeof(Test)
sería 4 × 3 = 12, aunque solo contiene 6 bytes de datos. El caso de uso más común para el #pragma
(que yo sepa) es cuando se trabaja con dispositivos de hardware en los que debe asegurarse de que el compilador no inserte relleno en los datos y cada miembro siga al anterior. Con #pragma pack(1)
la estructura anterior se presentaría así:
| 1 |
| AA(1) |
| BB(1) |
| BB(2) |
| BB(3) |
| BB(4) |
| CC(1) |
Y sizeof(Test)
sería 1 × 6 = 6.
Con #pragma pack(2)
la estructura anterior se presentaría así:
| 1 | 2 |
| AA(1) | pad.. |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
| CC(1) | pad.. |
Y sizeof(Test)
sería 2 × 4 = 8.
El orden de las variables en struct también es importante. Con variables ordenadas como sigue:
struct Test
{
char AA;
char CC;
int BB;
};
y con #pragma pack(2)
la estructura quedaría así:
| 1 | 2 |
| AA(1) | CC(1) |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
y sizeOf(Test)
sería 3 × 2 = 6.

nmichaels
#pragma
se usa para enviar mensajes no portátiles (solo en este compilador) al compilador. Cosas como deshabilitar ciertas advertencias y empaquetar estructuras son razones comunes. Deshabilitar advertencias específicas es particularmente útil si compila con el indicador de advertencias como errores activado.
#pragma pack
específicamente se usa para indicar que la estructura que se empaqueta no debe tener sus miembros alineados. Es útil cuando tiene una interfaz mapeada en memoria a una pieza de hardware y necesita poder controlar exactamente dónde apuntan los diferentes miembros de la estructura. En particular, no es una buena optimización de la velocidad, ya que la mayoría de las máquinas son mucho más rápidas para manejar datos alineados.
Para deshacer luego envolver #pragma pack(push,1)
y #pragma pack(pop)
Le dice al compilador el límite para alinear los objetos en una estructura. Por ejemplo, si tengo algo como:
struct foo {
char a;
int b;
};
Con una máquina típica de 32 bits, normalmente “querría” tener 3 bytes de relleno entre a
y b
así que eso b
aterrizará en un límite de 4 bytes para maximizar su velocidad de acceso (y eso es lo que normalmente sucederá de manera predeterminada).
Sin embargo, si tiene que hacer coincidir una estructura definida externamente, querrá asegurarse de que el compilador establezca su estructura exactamente de acuerdo con esa definición externa. En este caso, puede darle al compilador una #pragma pack(1)
para contarlo no para insertar cualquier relleno entre miembros — si la definición de la estructura incluye relleno entre miembros, lo inserta explícitamente (por ejemplo, típicamente con miembros llamados unusedN
o ignoreN
o algo por el estilo).
He visto a personas usarlo para asegurarse de que una estructura tome una línea de caché completa para evitar el intercambio falso en un contexto de subprocesos múltiples. Si va a tener una gran cantidad de objetos que se empaquetarán libremente de forma predeterminada, podría ahorrar memoria y mejorar el rendimiento de la memoria caché para empaquetarlos más apretados, aunque el acceso a la memoria no alineado generalmente ralentizará las cosas, por lo que podría haber un inconveniente.
El compilador podría alinear miembros en estructuras para lograr el máximo rendimiento en una determinada plataforma. #pragma pack
directiva le permite controlar esa alineación. Por lo general, debe dejarlo por defecto para un rendimiento óptimo. Si necesita pasar una estructura a la máquina remota, generalmente usará #pragma pack 1
para excluir cualquier alineación no deseada.

Ponto Gagge
Los elementos de datos (p. ej., miembros de clases y estructuras) normalmente se alinean en los límites de WORD o DWORD para los procesadores de la generación actual con el fin de mejorar los tiempos de acceso. Recuperar un DWORD en una dirección que no es divisible por 4 requiere al menos un ciclo de CPU adicional en un procesador de 32 bits. Entonces, si tiene, por ejemplo, tres miembros char char a, b, c;
en realidad tienden a ocupar 6 o 12 bytes de almacenamiento.
#pragma
le permite anular esto para lograr un uso de espacio más eficiente, a expensas de la velocidad de acceso, o para la consistencia de los datos almacenados entre diferentes objetivos del compilador. Me divertí mucho con esta transición de código de 16 bits a 32 bits; Espero que la migración a código de 64 bits cause el mismo tipo de dolores de cabeza para algunos códigos.

clifford
un compilador puede colocar miembros de la estructura en límites de bytes particulares por razones de rendimiento en una arquitectura particular. Esto puede dejar relleno sin usar entre los miembros. El empaquetamiento de la estructura obliga a los miembros a ser contiguos.
Esto puede ser importante, por ejemplo, si necesita que una estructura se ajuste a un archivo o formato de comunicaciones en particular donde los datos que necesita estén en posiciones específicas dentro de una secuencia. Sin embargo, dicho uso no se ocupa de los problemas de endianidad, por lo que, aunque se use, es posible que no sea portátil.
También puede superponerse exactamente a la estructura de registro interna de algún dispositivo de E/S, como un UART o un controlador USB, por ejemplo, para que el acceso al registro sea a través de una estructura en lugar de direcciones directas.
Fuerza una alineación/empaquetado particular de una estructura, pero como todos
#pragma
directivas que están definidas por la implementación.– sueño relajado
23 de julio de 2010 a las 13:20