2009-10-08 11 views
39

Para algunos compiladores, hay un especificador de relleno para estructuras, por ejemplo ::Visual C++ equivalente de __attribute__ de GCC ((__packed__))

 
RealView ARM compiler has "__packed" 
Gnu C Compiler has "__attribute__ ((__packed__))" 
Visual C++ has no equivalent, it only has the "#pragma pack(1)" 

Necesito algo que me puedo poner en la definición struct .

¿Alguna información/truco/sugerencia? TIA ...

+1

@Caspin: Quiero empacar toda la estructura. @Otras: Quiero tener un #define (de hecho 2) para lograr esto para los compiladores que usaré. #pragma truco no funciona en algunos de ellos. – Malkocoglu

+0

Tenga en cuenta que gcc ha admitido '#pragma pack' al menos desde la versión 4.0; no estoy seguro sobre RealView ARM. – Tom

Respuesta

22

no sé una forma de mancha de hacerlo, pero lo que pueda hacer algo horrible como esto:

#include "packed.h" 
struct Foo { /* members go here */ } PACKED; 
#include "endpacked.h" 

Luego de MSVC, packed.h:

#define PACKED 
#pragma pack(push,1) 

endpacked. h

#pragma pack(pop) 
#undef PACKED 

Para gcc, packed.h:

#define PACKED __attribute__ ((__packed__)) 

endpacked.h:

#undef PACKED 

Fundamentalmente, el embalaje es demasiado dependiente de la plataforma. Supongamos que su estructura empaquetada tiene campos de 8 bits y considera algún sistema con un byte de 16 bits. No puede tener una estructura que represente los datos simplemente empaquetando; debería saber cómo los bytes de 8 bits se convierten en bytes de 16 bits cuando se transfieren entre los dos sistemas. La estructura en la máquina de 16 bits puede necesitar campos de bits, en cuyo caso debe saber cómo la implementación los establece.

Por lo tanto, si el código está destinado a ser generalmente portátil, puede que simplemente tenga que definir las estructuras empaquetadas que necesita en una sección específica de la plataforma de su archivo de encabezado. O más bien, estructure su código para que un puerto futuro pueda hacer eso si es necesario.

+2

Técnicamente, podría hacer todo eso en un encabezado: '#ifndef PACKED' /' #define PACKED'/'#else/*! PACKED * /'/'#undef PACKED' /' #endif/* PACKED */'y luego incluya el mismo encabezado dos veces, una para habilitar y otra para deshabilitar. La utilidad/limpieza/cordura de tal práctica es discutible, pero también lo es la práctica que sugieres. –

+7

Creo que tomaré "begin/end must match", over "debe hacerse una cantidad par de veces", gracias ;-). Como dije en la respuesta, en principio necesita una definición de estructura específica de la plataforma. En la práctica, sin embargo, esto cubre los tres compiladores que actualmente le interesan a la persona que pregunta, permite más elementos comunes que solo copiar y pegar, y no es espectacularmente horrible en comparación con un enjambre de '# si _WIN32 #elif __GNUC__' y así sucesivamente alrededor de cada definición de estructura. '# include' es la forma correcta/única en C para abstraer o reutilizar un fragmento de código que contiene directivas de preprocesador. –

2

¿Por qué necesitas algo para entrar en la estructura?

Creo que #pragma pack(1) es lo mismo o me estoy perdiendo algo?

Usted puede hacer esto:

struct Foo 
{ 
#pragma pack(push, 1) 
int Bar; 
#pragma pack(pop) 
}; 

Pero se ve feo.

+10

En realidad es #pragma pack (push, 1) y #pragma pack (pop). – Timbo

58

Puede definir PAQUETE como este para GNU gcc

#define PACK(__Declaration__) __Declaration__ __attribute__((__packed__)) 

y como este para Visual C++:

#define PACK(__Declaration__) __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop)) 

Y utilizar de esta manera:

PACK(
struct myStruct 
{ 
    int a; 
    int b; 
}); 
+1

Originalmente estaba pensando que esto no funcionaba para las estructuras typedef'd, pero podría ser así si escribedef PACK (struct {int a;}) foo ;. Creo que eso dependería de la sintaxis #pragma/__ pragma del compilador en cuestión. Sin embargo, no funcionará para las enumeraciones, ya que están separadas internamente con comas (sí, las enumeraciones se pueden empaquetar y a veces es la forma más limpia de resolver su problema). –

+1

Este enfoque fue utilizado por Symbian para todos esos atributos, ya que se dirigían a muchos compiladores y algunos querían el bit específico del compilador escrito antes de un identificador, otros después, etc. – Will

+2

Me gusta esta solución, sin embargo, me tomó mucho tiempo descubra que MSVC++ maneja bitfields un poco diferente que GCC. Estaba usando bitfields "int" de varios tamaños (1, 7, 8, 16) y descubrí que MSVC++ aún quería empacar todo en límites de 4 bytes. Al convertir a char para 1,7, y 8 y abreviar para 16, obtuve el embalaje que esperaba. – Compholio

13

Sé que esto la pregunta es vieja ahora, pero creo que hay una solución mejor que las publicadas anteriormente. Es posible poner el pragma en el caso de MSVC en la línea de declaración de estructura después de todo.Considere lo siguiente:

#ifdef _MSC_VER 
# define PACKED_STRUCT(name) \ 
    __pragma(pack(push, 1)) struct name __pragma(pack(pop)) 
#elif defined(__GNUC__) 
# define PACKED_STRUCT(name) struct __attribute__((packed)) name 
#endif 

Entonces esto puede ser usado de esta manera:

typedef PACKED_STRUCT() { short a; int b } my_struct_t; 
PACKED_SRUCT(my_other_struct) { short a; int b }; 

etc.

La clave aquí es que el uso de la __pragma sólo tiene que ser alrededor de la línea de declaración de la estructura Esto necesita incluir el nombre de la estructura si se le da uno, de ahí que el nombre sea un parámetro para la macro. Por supuesto, esto es fácil de extender a enum/class, ¡que dejaré como ejercicio para el lector!

El programa de prueba en el pack documentation MSDN page es útil para verificar esto.

EDITAR

Resulta que en mi prueba de que estaba usando el compilador de Intel en Windows. Usando icl.exe, este enfoque funciona sin problemas, pero con el compilador de Microsoft (cl.exe), no (probado con 2010 y 2013).

+0

Me encantaría que esto realmente funcionara, ya que mantendría la macro rareza limitada a la línea de apertura de la definición de estructura, pero cuando probé esto en MSVS 2010 con C++, obtuve 'error C2143: error de sintaxis: falta '; ' antes de '{' '. Tuve que volver a algo parecido a la publicación de Steph, donde todo el cuerpo de la definición de estructura es el argumento macro, que es una mierda. Especialmente porque confunde el color de contexto vim en archivos C (vim lo maneja bien con archivos C++, no sé por qué). – phonetagger

+0

tampoco _ funciona bajo MSVC 2015. –

+0

Sin embargo, el 'PACKED_STRUCT' como palabra clave es genial.Se puede combinar con una solución de Steph como esto: '#ifdef _MSC_VER' ' # define PACKED_STRUCT (__Declaration__) __pragma (paquete (empuje, 1)) struct __Declaration__ __pragma (paquete (pop)) '' #elif definido (__GNUC __) '' # define PACKED_STRUCT (__Declaration__) struct __Declaration__ __attribute __ ((__ __ lleno)) '' # endif' Editado: bloques de código no se representan como se esperaba. Lo siento. –

6

Otra solución, según los compiladores que necesita admitir, consiste en observar que GCC ha admitido los pragmas de empaquetado al estilo Microsoft al menos desde la versión 4.0.4 (la documentación en línea está disponible en gnu.org para las versiones 3.4.6 y 4.0.4 - los pragmas no se describen en el primero y están en este último). Esto le permite simplemente usar #pragma pack(push,1) antes de una definición de estructura y #pragma pack(pop) después de la definición y se compilará en cualquiera de ellos.

+0

Confirmado para funcionar, pero la solución de IMHO @ Steph es mucho más elegante que poner pares de '# pragma' antes y después de cada declaración. –

5

Puede hacerlo al revés, ya que GCC es compatible con los pragmas relacionados con el paquete VC++. Mire here para más información.

Extraer ...

Para compatibilidad con los compiladores de Microsoft Windows, GCC soporta un conjunto de #pragma directivas que cambian el alineamiento máximo de miembros del estructuras (que no sean campos de bits de ancho cero), los sindicatos, y las clases definidas posteriormente. Siempre se requiere que el valor n de debajo sea una pequeña potencia de y especifica la nueva alineación en bytes.

#pragma pack(n) simplemente establece la nueva alineación.

#pragma pack() establece la alineación a la que estaba en vigor cuando se inició la compilación (ver opción de línea de comando también -fpack-struct[=<n>] ver Opciones Código GEN).

#pragma pack(push[,n]) empuja la configuración de alineación actual en una pila interna y luego establece opcionalmente la nueva alineación.

#pragma pack(pop) restaura la configuración de alineación a la guardada en la parte superior de la pila interna (y elimina esa entrada de la pila).

Tenga en cuenta que #pragma pack([n]) no influye en esta pila interna; por lo que es posible tener #pragma pack(push) seguido de múltiples #pragma pack(n) instancias y finalizado por un solo #pragma pack(pop).

Algunos objetivos, p.i386 y powerpc, admite el ms_struct#pragma que establece una estructura como la documentada __attribute__((ms_struct)).

#pragma ms_struct on activa el diseño de las estructuras declaradas.

#pragma ms_struct off desactiva el diseño de las estructuras declaradas.

#pragma ms_struct reset vuelve al diseño predeterminado.

Cuestiones relacionadas