2012-08-06 14 views
8

De this question uno podría comenzar a creer que la alineación de una unión no es menor que la alineación más grande de sus miembros individuales. Pero tengo un problema con el tipo long long en gcc/g ++. El ejemplo completo se puede encontrar here, pero aquí están las partes relevantes para mi pregunta:¿Por qué la alineación del miembro de unión largo largo es más grande que la unión/estructura contenedora? ¿Es esto correcto?

union ull { 
    long long m; 
}; 

struct sll { 
    long long m; 
}; 


int main() { 
#define pr(v) cout << #v ": " << (v) << endl 
    pr(sizeof(long long)); 
    pr(__alignof__(long long)); 
    pr(sizeof(ull)); 
    pr(__alignof__(ull)); 
    pr(sizeof(sll)); 
    pr(__alignof__(sll)); 
}; 

Esto se traduce en la siguiente salida:

sizeof(long long): 8 
__alignof__(long long): 8 
sizeof(ull): 8 
__alignof__(ull): 4 
sizeof(sll): 8 
__alignof__(sll): 4 

¿Por qué es la alineación de un miembro de un sindicato más grande de lo que se de la unión que contiene?

[ACTUALIZACIÓN]

Según la respuesta de Keith alignof está mal aquí. Pero pruebo lo siguiente y parece que alignof nos dice la verdad. Ver:

union ull { 
    long long m; 
}; 
long long a; 
char b; 
long long c; 
char d; 
ull e; 
int main() { 
#define pr(v) cout << #v ": " << (v) << endl 
    pr(size_t((void*)&b)); 
    pr(size_t((void*)&c)); 
    pr(size_t((void*)&d)); 
    pr(size_t((void*)&e)); 
    pr(size_t((void*)&c) - size_t((void*)&b)); 
    pr(size_t((void*)&e) - size_t((void*)&d)); 
}; 

La salida:

size_t((void*)&b): 134523840 
size_t((void*)&c): 134523848 
size_t((void*)&d): 134523856 
size_t((void*)&e): 134523860 
size_t((void*)&c) - size_t((void*)&b): 8 
size_t((void*)&e) - size_t((void*)&d): 4 

Así, la alineación de long long es 8 y la alineación de la unión que contiene long long es 4 en los datos globales. Para el ámbito local no puedo probar esto, ya que parece que el compilador puede reorganizar los datos locales, por lo que este truco no funciona. ¿Puedes comentar sobre esto?

[/ ACTUALIZACIÓN]

+1

Veo lo mismo en Red Hat, gcc 4.7.0 con '-m32', pero * no * con' -m64' (todos '8's). – BoBTFish

+1

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 un enlace al error gcc correspondiente para _Alignof (C11). –

Respuesta

7

__alignof__ (que es una extensión gcc) no necesariamente reportar la alineación requerido para un tipo.

x86 procesadores, por ejemplo, realmente no requieren más de 1 byte de alineación para cualquier tipo. El acceso a un objeto de 4 bytes u 8 bytes probablemente será más eficiente si el objeto está alineado con la palabra, pero la alineación de bytes es suficiente.

Citando al gcc documentation:

Algunas máquinas requieren en realidad nunca la alineación; permiten la referencia a cualquier tipo de datos incluso en una dirección impar. Para estas máquinas, __alignof__ informa la alineación más pequeña que GCC otorgará al tipo de datos , generalmente según lo ordenado por el ABI objetivo.

Pero eso todavía no responde la pregunta. Incluso con esa definición libre, no puedo pensar en ninguna buena razón para __alignof__ para indicar una alineación más estricta para long long que para una estructura o unión que contiene un long long.

Un método más portátil de la determinación de la alineación de un tipo es la siguiente:

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t))) 

Esto produce el desplazamiento de un miembro de tipo t en una estructura que consiste en una char y una t.El uso de este macro, este programa:

#include <iostream> 
#include <cstddef> 

union ull { 
    long long m; 
}; 

struct sll { 
    long long m; 
}; 

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t))) 

int main() { 
#define pr(v) std::cout << #v ": " << (v) << std::endl 
    pr(sizeof(long long)); 
    pr(__alignof__(long long)); 
    pr(ALIGNOF(long long)); 
    pr(sizeof(ull)); 
    pr(__alignof__(ull)); 
    pr(ALIGNOF(ull)); 
    pr(sizeof(sll)); 
    pr(__alignof__(sll)); 
    pr(ALIGNOF(sll)); 
}; 

produce esta salida en mi sistema (gcc-4.7, Ubuntu 12.04, x86):

sizeof(long long): 8 
__alignof__(long long): 8 
ALIGNOF(long long): 4 
sizeof(ull): 8 
__alignof__(ull): 4 
ALIGNOF(ull): 4 
sizeof(sll): 8 
__alignof__(sll): 4 
ALIGNOF(sll): 4 

Los resultados indicaron por mi ALIGNOF() macro son consistentes: long long tiene Alineación de 4 bytes, y una estructura o unión que contiene un long long tiene una alineación de 4 bytes.

Sospecho que esto es un error, o al menos una incoherencia, en la implementación de gcc de __alignof__. Pero la vaguedad de la definición hace que sea difícil estar seguro de que realmente es un error. It doesn't seem to have been reported.

Actualización:

I se pueden saltar el arma, pero yo sólo he presentado una bug report.

Este earlier bug report, cerrado como "NO VÁLIDO", es similar, pero no se refiere a la alineación de la estructura en sí.

Actualización 2:

Mi informe de error se ha cerrado como un duplicado de la anterior. Pediré una aclaración.

+0

Muchas gracias por este 'ALIGNOF()' sugerencia. – PiotrNycz

+0

Sin embargo, esta macro no funciona para los tipos NonPOD ya que offsetof no funciona con NonPOD (vea http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-non-pod-strucutures- Cª). ¿Conoces por casualidad la solución para los tipos NonPOD? – PiotrNycz

+0

puede comentar sobre mi actualización. Parece que '__alignof__ (long long) == 8' es correcto. Y lo que se prueba con su 'ALIGNOF' es simplemente alinear' long long' en 'struct', que es el mismo caso que mi' struct sll {long long m; } ' Tal vez esta ayuda para tu informe de errores. – PiotrNycz

Cuestiones relacionadas