2013-02-15 4 views
5

Si tratta dell'allineamento della memoria. Nel codice seguente, mi aspettavo che l'offset di b all'interno della struttura fosse 8 (macchina a 32 bit). Vedi here. Qui, rendendo b si verificano sempre all'interno di una linea della cache. Tuttavia, non è questo il caso. Il membro b in un oggetto globale di struct test1 sembra essere allineato. Non sono sicuro che il suo caso o compilatore lo faccia deliberatamente.Perché un membro doppio nella struttura non è allineato al limite di 8 byte?

Volevo capire perché il compilatore non riempie 4 byte dopo a.

struct test1 
{ 
int a; 
double b; 
}t1; 

int main() 
{ 
struct test1 *p = malloc(sizeof(struct test1)); 
printf("sizes int %d, float %d, double %d, long double %d\n", sizeof(int), sizeof(float), sizeof(double), sizeof(long double)); 
printf("offset of b %d\n",(int)&(t1.b)-(int)&(t1)); 

printf("\naddress of b (on heap) = %p, addr of b (on data seg) = %p\n",&(p->b), &(t1.b)); 

return 0; 
} 

L'uscita è ...

sizes int 4, float 4, double 8, long double 12 
offset of b 4 

address of b (on heap) = 0x804a07c, addr of b (on data seg) = 0x80497e0 

Sto usando il compilatore gcc di serie su Ubuntu 10.04

+0

Per prima cosa, se la CPU può trattare con operandi non allineati, non c'è nessun problema . Ora, il motivo per cui il compilatore è strettamente imballato strutture, è una domanda. Come stai compilando il codice?Ci sono delle opzioni di compilazione nascoste provenienti dai makefile o da qualunque cosa il compilatore potrebbe estrarre dai suoi file di configurazione? –

+0

@Alexey, no, è solo gcc test.c; ./a.out – Chethan

+0

Ottengo gli stessi risultati durante la compilazione con gcc 4.6.3 utilizzando le opzioni "predefinite" e -m32 (Ho un sistema operativo a 64-bit, quindi l'impostazione predefinita è 64-bit, e in quel caso, mi dà un allineamento di 8 byte). –

risposta

5

Secondo lo System V ABI for i386, pagina 28, double ottiene solo l'allineamento di 4 byte, ma i compilatori sono consigliati di fornire un'opzione per 8 byte. Sembra che questo sia ciò che viene implementato da GCC su Linux, l'opzione si chiama -malign-double.

Un'altra alternativa è quella di utilizzare -m64 per ottenere codice oggetto x86-64, che è già il default su alcuni sistemi, tra cui Mac OS X.

0

v'è alcuna garanzia circa l'allineamento, a tutti, in ANSI C.

L'allineamento avviene con le variabili automatiche più che con qualsiasi oggetto dichiarato nell'heap. Se sei su un sistema POSIX, usa memalign (3) per ricevere memoria che sei sicuro che sia allineato. Malloc può restituire memoria in qualsiasi offset. È possibile utilizzare le direttive del compilatore come __attribute__ ((__packed__)) per inserire i propri allineamenti.

4

Mi aspettavo che l'offset di b all'interno della struttura fosse 8 (macchina a 32 bit). Vedi qui

Le tue referenze spiegano perché potrebbe essere vantaggioso raddoppiare 8 allineamenti. Ciò non equivale a una garanzia che raddoppia sarà sempre allineata a 8. Se le tue fonti dicono che sono sempre allineate a 8 e osservi un'implementazione in cui non lo sono, le tue fonti sono sbagliate.

Dalla pagina man GCC:

Allineamento variabili "doppio" sul confine di due parole produrrà codice che viene eseguito po 'più veloce su un Pentium a scapito di più memoria.

Quindi la ragione dichiarata da GCC per il 4-allineamento è di risparmiare memoria. È possibile utilizzare -malign-double e -mno-align-double per controllarlo, sebbene si rischi naturalmente di creare incompatibilità binarie se si condividono le strutture tra codice compilato con opzioni in conflitto. Per particolari oggetti/membri struct è possibile utilizzare lo stesso GCC __attribute__((aligned)), _Alignas (in C11) o alignas (in C++ 11), ognuno dei quali può richiedere una costante intera per specificare l'allineamento richiesto.