2012-08-06 28 views
8

Von this question könnte man anfangen zu glauben, dass die Ausrichtung einer Union nicht weniger als die größte Ausrichtung der einzelnen Mitglieder ist. Aber ich habe ein Problem mit dem long long Typ in gcc/g ++. Das vollständige Beispiel kann here zu finden, aber hier sind die relevanten Teile für meine Frage:Warum ist das Ausrichten des langen langen Verbindungsglieds größer als dasjenige, das die Verbindung/Struktur enthält? Ist das richtig?

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)); 
}; 

Dieses in der folgenden Ausgabe führt:

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

Warum ist die Ausrichtung eines Verbindungsteils größer als die von der enthaltenden Union?

[UPDATE]

Laut Keith Antwort alignof ist hier falsch. Aber ich teste das Folgende und es scheint, dass alignof uns die Wahrheit sagt. Siehe:

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)); 
}; 

Der Ausgang:

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 

So ist die Ausrichtung von long long 8 und Ausrichtung der Union enthält long long 4 in globalen Daten. Für den lokalen Bereich kann ich das nicht testen, da es dem Compiler freisteht, lokale Daten neu anzuordnen - dieser Trick funktioniert also nicht. Kannst du das kommentieren?

[/ UPDATE]

+1

Ich sehe das gleiche auf Red Hat, gcc 4.7.0 mit '-m32', aber * nicht * mit' -m64' (alle '8's). – BoBTFish

+1

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 ein Link zum entsprechenden gcc-Bug für _Alignof (C11). –

Antwort

7

__alignof__ (die eine gcc Erweiterung ist) nicht unbedingt erforderlich berichten über die Ausrichtung für einen Typ.

X86-Prozessoren, zum Beispiel erfordern nicht wirklich mehr als 1-Byte-Ausrichtung für jeden Typ. Der Zugriff auf ein 4-Byte- oder 8-Byte-Objekt ist wahrscheinlich effizienter, wenn das Objekt wortausgerichtet ist, die Byte-Ausrichtung jedoch ausreichend ist.

unter Angabe der gcc documentation:

Einige Maschinen eigentlich nie Ausrichtung erfordern; Sie ermöglichen die Referenz zu jedem Datentyp auch an einer ungeraden Adresse. Für diese Maschinen meldet __alignof__ die kleinste Ausrichtung, die GCC dem Datentyp geben wird, normalerweise wie vom Ziel-ABI vorgegeben.

Aber das beantwortet noch nicht wirklich die Frage. Selbst mit dieser losen Definition kann ich mir keinen guten Grund vorstellen, dass __alignof__ eine strengere Ausrichtung für long long anzeigt als für eine Struktur oder eine Union, die eine long long enthält. Diese

Ein tragbares Verfahren zur Bestimmung der Ausrichtung eines Typs bestimmt, ist:

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

Dies ergibt den Versatz eines Elements des Typs t in einer Struktur, bestehend aus einem char und einem t.Mit diesem Makro, dieses Programm:

#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)); 
}; 

erzeugt diese Ausgabe auf meinem System (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 

Die Ergebnisse zeigten, durch meine ALIGNOF() Makro sind konsistent: long long hat 4-Byte-Ausrichtung, und eine Struktur oder Union, die eine long long enthält, hat 4-Byte-Ausrichtung.

Ich vermute, das ist ein Fehler, oder zumindest eine Inkonsistenz, in GCC-Implementierung von __alignof__. Aber die Unbestimmtheit der Definition macht es schwer, sicher zu sein, dass es wirklich ein Fehler ist. It doesn't seem to have been reported.

Update:

ich die Waffe springen kann, aber ich habe gerade einen bug report vorgelegt.

Diese earlier bug report, geschlossen als "INVALID", ist ähnlich, aber es bezieht sich nicht auf die Ausrichtung der Struktur selbst.

Update 2:

Mein Bug-Report als Duplikat des einen wurde früher geschlossen. Ich werde um Klärung bitten.

+0

Vielen Dank für diesen 'ALIGNOF()' Hinweis. – PiotrNycz

+0

Dieses Makro funktioniert jedoch nicht für NonPOD-Typen, da offsetof nicht mit NonPOD funktioniert (siehe http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-no-pod-strucures-s- in-c). Kennst du zufällig eine Lösung für NonPOD-Typen? – PiotrNycz

+0

können Sie mein Update kommentieren. Es scheint, dass "__alignof __ (long long) == 8" korrekt ist. Und was mit Ihrem 'ALIGNOF' getestet wird, ist nur das Ausrichten von' long long' in 'struct', das ist der gleiche Fall wie mein' struct sll {long long m; } '. Vielleicht diese Hilfe für deinen Fehlerbericht. – PiotrNycz