2014-10-15 8 views
6

Ho fatto il seguente codice come esempio.Perché un uint64_t ha bisogno di più memoria di 2 uint32_t quando utilizzato in una classe? E come prevenirlo?

#include <iostream> 

struct class1 
{ 

    uint8_t  a; 
    uint8_t  b; 
    uint16_t c; 
    uint32_t d; 
    uint32_t e; 

    uint32_t f; 
    uint32_t g; 
}; 

struct class2 
{ 

    uint8_t  a; 
    uint8_t  b; 
    uint16_t c; 
    uint32_t d; 
    uint32_t e; 

    uint64_t f; 
}; 

int main(){ 
    std::cout << sizeof(class1) << std::endl; 
    std::cout << sizeof(class2) << std::endl; 
    std::cout << sizeof(uint64_t) << std::endl; 
    std::cout << sizeof(uint32_t) << std::endl; 
} 

stampe

20 
24 
8 
4 

Quindi è abbastanza semplice per vedere che uno uint64_t è grande come due uint32_t di, perché di classe 2, avrà 4 byte in più, se sono la stessa tranne che per la sostituzione di due uint32_t per un uint64_t.

+5

Allineamento. 'class2' deve essere allineato a 8 byte. 'class1' no. –

+2

Fondamentalmente succede solo per come costruisci le tue lezioni. Poiché 'uint64_t' deve essere allineato, il compilatore deve gettare 4 byte di padding in' class2' (dopo la variabile 'e') – UnholySheep

+3

Puoi anche riorganizzare le strutture per avere i campi in ordine decrescente di dimensioni, quindi il padding i problemi non appariranno poiché i campi più grandi sono già su un allineamento di byte carino, e lo trasferiranno nei campi di minore dimensione. –

risposta

6

Come è stato sottolineato, ciò è dovuto a padding.

Per evitare ciò, è possibile utilizzare

#pragma pack(1) 

class ... { 

}; 
#pragma pack(pop) 

Racconta il compilatore di allineare non a 8 byte, ma a un byte. Il comando pop lo disattiva (questo è molto importante, poiché se lo fai nell'intestazione e qualcuno include la tua intestazione, potrebbero verificarsi errori molto strani)

+0

La domanda è "perché sta succedendo", non "cosa dovrei fare a riguardo". Menzionare #pragma pack' è davvero un argomento, ma dovresti anche spiegare (e non solo linkare) la vera causa. – Angew

+2

In alternativa, può modificare l'ordine delle variabili nella sua definizione di classe. – UnholySheep

+2

Inoltre, '#pragma pack' è specifico del compilatore (anche se potrebbe essere ampiamente supportato) –

1

La regola per l'allineamento (su x86 e x86_64) è generalmente a allinea una variabile sulla sua dimensione.

In altre parole, variabili a 32 bit sono allineati su 4 byte, variabili a 64 bit di 8 byte, ecc

L'offset di f è 12, quindi in caso di uint32_t f è necessaria alcuna imbottitura, ma quando f è un uint64_t, vengono aggiunti 4 byte di riempimento per ottenere f da allineare su 8 byte.

Per questo motivo è meglio ordinare i membri dei dati dal più grande al più piccolo. Quindi non ci sarebbe alcuna necessità di imbottitura o imballaggio.

Problemi correlati