2010-11-29 7 views
11

¿Cómo puedo desactivar el relleno de estructura en C sin usar pragma?Desactivar el relleno de estructura en C sin usar pragma

+0

Esto no es estándar. Si (y, si es así, cómo) esto es posible depende completamente de la implementación de C que esté utilizando. –

+0

Creo que no hay otra manera de hacer esto. – frast

+0

¿Por qué no puedes usar pragma? –

Respuesta

16

no existe una norma forma de hacer esto. La norma establece que el relleno se puede hacer a discreción de la implementación. De C99 6.7.2.1 Structure and union specifiers, párrafo 12:

Cada miembro no campo de bits de una estructura o unión objeto está alineado de una manera definida por la implementación apropiada a su tipo.

Habiendo dicho eso, hay un par de cosas que puedes probar.


El primero que ya ha descontado, usando #pragma para tratar de convencer al compilador que no empacar. En cualquier caso, esto no es portátil. Tampoco existen otras formas específicas de implementación, pero debe verificarlas, ya que puede ser necesario hacerlo si realmente necesita esta capacidad.


La segunda es de pedir sus campos de mayor a menor orden, como todos los tipos long long seguidos por los long queridos, entonces todos los int, short y finalmente char tipos. Por lo general, esto funcionará, ya que con mayor frecuencia son los tipos más grandes los que tienen los requisitos de alineación más estrictos. De nuevo, no es portátil.


En tercer lugar, puede definir sus tipos como char matrices y emitir las direcciones para asegurar que no hay relleno. Pero tenga en cuenta que algunas arquitecturas se ralentizarán si las variables no están alineadas correctamente y otras fallarán miserablemente (como por ejemplo, al generar un error de BUS y al finalizar su proceso).

Este último contiene algunas explicaciones adicionales. Digamos que tiene una estructura con los campos en el orden siguiente:

char C; // one byte 
int I; // two bytes 
long L; // four bytes 

con relleno, que puede terminar con los siguientes bytes:

CxxxIIxxLLLL 

donde x es el relleno.

Sin embargo, si se define su estructura como:

typedef struct { char c[7]; } myType; 
myType n; 

que se obtiene:

CCCCCCC 

A continuación, puede hacer algo como:

int *pInt = &(n.c[1]); 
int *pLng = &(n.c[3]); 
int myInt = *pInt; 
int myLong = *pLng; 

a DOY:

CIILLLL 

De nuevo, desafortunadamente, no es portátil.


Todas estas "soluciones" que se basan en tener un conocimiento íntimo de su compilador y los tipos de datos subyacentes.

+1

Nota, en algunos sistemas que acceden a direcciones desalineadas ('int * pLng = & (n.c [3]); int myLong = * pLng;' fallará en absoluto (por ejemplo, 68000 y ARM fallará). Entonces se requiere relleno allí. – Vovanium

+0

De acuerdo, @Vovanium, de ahí mi comentario de "fracasar miserablemente". – paxdiablo

3

Aparte de las opciones del compilador como pragma pack, no se puede, el relleno está en el estándar C.

Siempre se puede tratar de reducir el acolchado al declarar los tipos más pequeños pasada en la estructura como en:

struct _foo { 
    int a; /* No padding between a & b */ 
    short b; 
} foo; 

struct _bar { 
    short b; /* 2 bytes of padding between a & b */ 
    int a; 
} bar; 

Nota para las implementaciones que tienen límites de 4 bytes

1

En algunas arquitecturas, la propia CPU se opondrá si se le solicita trabajar con datos mal alineados. Para evitar esto, el compilador podría generar múltiples instrucciones de lectura o escritura alineadas, desplazar y dividir o combinar los diversos bits. Es razonable esperar que sea 5 o 10 veces más lento que el manejo de datos alineado. Pero, el Estándar no requiere que los compiladores estén preparados para hacer eso ... dado el costo de rendimiento, simplemente no tiene suficiente demanda. Los compiladores que admiten control explícito sobre el relleno proporcionan sus propios pragmas precisamente porque los pragmas están reservados para la funcionalidad no estándar.

Si debe trabajar con datos no rellenos, considere escribir sus propias rutinas de acceso. Es posible que desee experimentar con tipos que requieren menos alineación (por ejemplo, use char/int8_t), pero aún es posible que, p. el tamaño de las estructuras se redondeará a múltiplos de 4, lo que frustraría las estructuras de embalaje con fuerza, en cuyo caso deberá implementar su propio acceso para toda la región de la memoria.

0

O bien le permite al compilador hacer el relleno, o le dice que no lo haga usando #pragma, o bien usa algunos grupos como una matriz de caracteres, y construye todos sus datos usted mismo (desplazando y agregando bytes). Esto es realmente ineficiente, pero controlarás exactamente el diseño de los bytes. Lo hice a veces preparando paquetes de red a mano, pero en la mayoría de los casos es una mala idea, incluso si es estándar.

0

Si realmente quiere estructuras sin relleno: defina tipos de datos de reemplazo para abreviar, int, largo, etc., utilizando estructuras o clases que están compuestas solo de bytes de 8 bits. Luego, componga sus estructuras de nivel superior utilizando los tipos de datos de reemplazo.

La sobrecarga del operador de C++ es muy conveniente, pero se podría lograr el mismo efecto en C usando estructuras en lugar de clases. Las implementaciones de reparto y asignación siguientes suponen que la CPU puede manejar enteros desalineados de 32 bits, pero otras implementaciones podrían acomodar CPU más estrictas.

Aquí es código de ejemplo:

#include <stdint.h> 
#include <stdio.h> 

class packable_int { public: 

    int8_t b[4]; 

    operator int32_t() const  { return *(int32_t*) b; } 
    void operator = (int32_t n) { *(int32_t*) b = n; } 

}; 

struct SA { 
    int8_t c; 
    int32_t n; 
} sa; 

struct SB { 
    int8_t  c; 
    packable_int n; 
} sb; 

int main() { 
    printf ("sizeof sa %d\n", sizeof sa); // sizeof sa 8    
    printf ("sizeof sb %d\n", sizeof sb); // sizeof sb 5    
    return 0; 
} 
0

Podemos desactivar el relleno estructura en el programa de c utilizando cualquiera de los métodos siguientes.

-> use __attribute__((packed)) detrás de la definición de structure. por ej.

struct node { 
    char x; 
    short y; 
    int z; 
} __attribute__((packed)); 

-> use -fpack-struct marca mientras compila el código c. por ej.

$ gcc -fpack-struct -o tmp tmp.c

Espero que esto ayude. Gracias.

Cuestiones relacionadas