2011-06-05 13 views
10

Imagine una estructura compuesta por valores de miembro de 32 bits, 16 bits y 8 bits. Donde el orden de los valores de los miembros es tal que cada miembro se encuentra en su límite natural.alineación de miembro de estructura: ¿es posible suponer que no hay relleno

struct Foo 
{ 
    uint32_t a; 
    uint16_t b; 
    uint8_t c; 
    uint8_t d; 
    uint32_t e; 
}; 

Alineación de miembros y reglas de relleno son documented para Visual C++. sizeof (Foo) en VC++ la estructura anterior es previsiblemente "12".

Ahora, estoy bastante seguro de que la norma es que no se deben hacer suposiciones sobre relleno y alineamiento, pero en la práctica, ¿otros compiladores en otros sistemas operativos ofrecen garantías similares?

Si no, ¿hay un equivalente de "# paquete de pragma (1)" en GCC?

+0

En C, 'Foo', en' sizeof (Foo) ', no está declarado. La expresión es un error (a menos que 'Foo' esté definido/declarado en otro lugar).Sugiero que no intente escribir archivos fuente en varios idiomas: las desventajas son mucho mayores que cualquier pro que pueda encontrar. – pmg

+0

@pmg: pedantería. :) 'typedef struct Foo {...} Foo;' – Xeo

+0

Creo que el 'typedef' es redundante (y por lo tanto una fuente de errores que se puede quitar de forma segura) en C++. Mi punto sigue siendo: escribir archivos fuente en varios idiomas es más problemático de lo que vale. – pmg

Respuesta

6

En los sistemas que realmente ofrecen esos tipos, es muy probable que funcione. En, digamos, un sistema de 36 bits, esos tipos no estarían disponibles en primer lugar.

GCC proporciona un atributo

__attribute__ ((packed))

Con efecto similar.

+0

No depende realmente del tipo de letra, sino que depende de la arquitectura. Por ejemplo, algunos procesadores de 16 o 32 bits no pueden direccionar directamente una dirección de 8 bits, por lo que sin relleno puede tener que generar instrucciones adicionales de desplazamiento y máscara para extraer un valor de 8 bits de una lectura de memoria de 16 o 32 bits. Esta situación es mucho más común que su hipotético sistema de 36 bits (ARM7, por ejemplo). – Clifford

+0

@Clifford: no es común. El compilador ya debe generar código para direccionar un tipo de 8 bits si existe (porque nunca se puede alinear en matrices), por lo que no es una restricción adicional. En general, "la alineación" de un tipo nunca puede ser mayor que su tamaño (y debe dividir su tamaño), por lo que sería patológico que un compilador imponga una alineación mayor cuando el tipo se utiliza en una estructura. –

+0

No estaba diciendo que el compilador no podía o no generaría código para accesos de 8 bits cuando fuera necesario, más bien por razones de rendimiento lo evitaría para una estructura. Se garantiza que una matriz sea contigua, una estructura no. Sugeriría que ARM7 es lo suficientemente común, pero ya que está etiquetado como Linux, no tanto en este contexto. – Clifford

7

En general, tiene razón en que no es una suposición segura, aunque a menudo obtendrá el embalaje que espera en muchos sistemas. Es posible que desee utilizar el atributo packed en sus tipos cuando usa gcc.

E.g.

struct __attribute__((packed)) Blah { /* ... */ }; 
+0

Esto es bastante peligroso y completamente innecesario. Ver mi respuesta –

+0

@R ..: Estoy completamente de acuerdo. –

5

En la práctica, en cualquier sistema en el que existen los tipos uintXX_t, recibirá la alineación deseada sin relleno. No arroje feos gcc-ismos para tratar de garantizarlo.

Editar: dar más detalles sobre por qué puede ser perjudicial para usar attribute packed o aligned, puede hacer que la estructura entera a estar desalineado cuando se utiliza como un miembro de una estructura más grande o en la pila. Esto definitivamente afectará el rendimiento y, en máquinas que no sean x86, generará un código mucho más grande. También significa que es inválido para tomar un puntero a cualquier miembro de la estructura, ya que el código que accede al valor a través de un puntero no será consciente de que podría estar desalineado y, por lo tanto, podría fallar.

En cuanto a por qué no es necesario, tenga en cuenta que attribute es específico de los compiladores gcc y gcc-workalike. El estándar C no deja la alineación indefinida o no especificada. Es implementación definida lo que significa que la implementación es necesaria para especificar y documentar aún más cómo se comporta. El comportamiento de gcc es, y siempre ha sido, alinear cada miembro de la estructura en el siguiente límite de su alineación natural (la misma alineación que tendría cuando se utiliza fuera de una estructura, que es necesariamente un número que divide el tamaño del tipo) . Como attribute es una función de gcc, si la usas ya estás asumiendo un compilador de tipo gcc, pero suponiendo que ya tienes la alineación que deseas.

Cuestiones relacionadas