2012-08-06 10 views
8

Da this question si potrebbe iniziare a credere che l'allineamento di un'unione non sia inferiore al più grande allineamento dei suoi singoli membri. Ma ho un problema con il tipo long long in gcc/g ++. L'esempio completo può essere trovato here, ma qui ci sono le parti rilevanti per la mia domanda:Perché l'allineamento del long union member è più grande del union/struct che lo contiene? È corretto?

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

Il risultato è il seguente output:

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

Perché è l'allineamento di un membro di un'unione più grande di quella dell'unione contenente?

[UPDATE]

Secondo la risposta di Keith alignof è sbagliato qui. Ma provo quanto segue e sembra che l'allineamento ci dica il vero. Vedere:

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

L'output:

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 

Così, l'allineamento del long long è 8 e l'allineamento di unione contenente long long è 4 nei dati globali. Per ambito locale non posso testarlo poiché sembra che il compilatore sia libero di riorganizzare i dati locali, quindi questo trucco non funziona. Puoi commentare questo?

[/ UPDATE]

+1

Vedo la stessa cosa su Red Hat, gcc 4.7.0 con '-m32', ma * non * con' -m64' (tutti '8's). – BoBTFish

+1

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 un collegamento al bug gcc corrispondente per _Alignof (C11). –

risposta

7

__alignof__ (che è un'estensione gcc) non necessariamente segnalare l'allineamento richiesto per un tipo.

I processori x86, ad esempio, non richiedono realmente più di un byte di allineamento per alcun tipo. L'accesso a un oggetto a 4 o 8 byte sarà probabilmente più efficiente se l'oggetto è allineato alla parola, ma l'allineamento dei byte è sufficiente.

Citando il gcc documentation:

Alcune macchine mai effettivamente richiedono l'allineamento; consentono il riferimento a qualsiasi tipo di dati anche a un indirizzo dispari. Per queste macchine, __alignof__ riporta il più piccolo allineamento che GCC fornirà al tipo di dati , solitamente come richiesto dall'ABI di destinazione.

Ma ancora non risponde alla domanda. Anche con quella definizione allentata, non riesco a pensare a una buona ragione per __alignof__ per indicare un allineamento più severo per long long che per una struttura o unione contenente uno long long.

Un metodo più portatile per determinare l'allineamento di un tipo è questo:

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

questo produce l'offset di un membro di tipo t in una struttura costituita da un char e t.Utilizzando questa macro, questo programma:

#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 questo output sul mio sistema (gcc-4.7, Ubuntu 12.04, 86):

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 

I risultati hanno indicato dal mio ALIGNOF() macro sono coerenti: long long ha Allineamento a 4 byte e una struttura o unione contenente uno long long ha un allineamento di 4 byte.

Ho il sospetto che si tratti di un bug o di un'incoerenza nell'implementazione di gcc di __alignof__. Ma la vaghezza della definizione rende difficile essere certi che sia davvero un bug. It doesn't seem to have been reported.

Aggiornamento:

I possono essere saltare la pistola, ma ho appena presentato una bug report.

Questo earlier bug report, chiuso come "NON VALIDO", è simile, ma non si riferisce all'allineamento della struttura stessa.

Aggiornamento 2:

mio bug report è stato chiuso come un duplicato di quella precedente. Chiederò dei chiarimenti.

+0

Grazie mille per questo suggerimento 'ALIGNOF()'. – PiotrNycz

+0

Tuttavia questa macro non funziona con i tipi NonPOD poiché offsetof non funziona con NonPOD (consultare http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-non-pod-strucutures- in-c). Per caso conosci la soluzione per i tipi di NonPOD? – PiotrNycz

+0

puoi commentare il mio aggiornamento. Sembra che '__alignof __ (long long) == 8' sia corretto. E ciò che viene testato con il tuo 'ALIGNOF'è proprio l'allineamento di' long long' in 'struct', che è lo stesso del mio' struct sll {long long m; } '. Forse questo aiuto per la segnalazione del bug. – PiotrNycz