2013-09-04 11 views
6

Na przykładW jaki sposób kompilator określa rozmiar struktury bitfield?

struct a { 
    uint32_t foreColor_ : 32; 
    uint32_t backColor_ : 32; 
    uint16_t lfHeight_ : 16; 
    uint16_t flags_: 4; 
    bool lfBold_: 1; 
    bool lfItalic_: 1; 
    bool lfUnderLine_: 1; 
    bool lfDashLine_: 1; 
    bool lfStrike_: 1; 
    bool lfSubscript_: 1; 
    bool lfSuperscript_: 1; 
}; 

wynosi 16 bajtów, ale

struct a { 
    uint32_t foreColor_ : 32; 
    uint32_t backColor_ : 32; 
    uint16_t lfHeight_ : 16; 
    uint8_t  flags_: 4; 
    bool lfBold_: 1; 
    bool lfItalic_: 1; 
    bool lfUnderLine_: 1; 
    bool lfDashLine_: 1; //for ime 
    bool lfStrike_: 1; 
    bool lfSubscript_: 1; 
    bool lfSuperscript_: 1; 
}; 

ma długość 12 bajtów.

Pomyślałem, że flags_ powinny mieć tę samą długość, ale wygląda na to, że nie.

Dlaczego?

+0

Czy używanie typów takich jak 'uint32_t' dla pola bitowego nie jest zbyt głupie? (Zwykle powinny być używane tylko wtedy, gdy trzeba dokładnie dopasować format zewnętrzny, a nawet wtedy ich użycie jest wątpliwe.) –

Odpowiedz

6

normy (9.6 the working draft) mówi, to:

określa dla pola; jego długość jest wybierana z nazwy pola bitowego przez dwukropek. Atrybut pola bitowego nie należy do typu klasy . Stała ekspresja musi być stałą wartością stałą o wartości większej lub równej zeru. Stała ekspresja może być większa niż liczba bitów w reprezentacji obiektów typu ( 3.9) typu pola bitowego; w takich przypadkach dodatkowe bity są używane jako bity dopełniające i nie uczestniczą w reprezentacji wartości pola bitowego ( 3.9). Przydział pól bitowych w obiekcie klasy jest definiowany przez implementację. Wyrównanie pól bitowych to zdefiniowane przez implementację. Pola bitowe są zapakowane w jakąś adresowalną jednostkę alokacji . [Uwaga: Jednostki alokacji bitów na niektórych maszynach , a nie na innych. Pola bitowe są przypisywane od prawej do lewej na niektórych maszynach, od lewej do prawej na innych. -end uwaga]

(podkreślenie moje)

Więc to zależy od kompilatora. To, co zdarza się w twoim przypadku - a opisałbym to jako dość normalne zachowanie - polega na tym, że łączy tylko pola bitowe tego samego typu, a następnie pakuje strukturę do granicy 4-bajtowej, więc w pierwszym przypadku mamy:

struct a { 
    uint32_t foreColor_ : 32; // 4 bytes (total) 
    uint32_t backColor_ : 32; // 8 bytes 
    uint16_t lfHeight_ : 16; // 10 bytes 
    uint16_t flags_: 4;  // 12 bytes 
    bool lfBold_: 1;   // 13 bytes 
    bool lfItalic_: 1; 
    bool lfUnderLine_: 1; 
    bool lfDashLine_: 1; 
    bool lfStrike_: 1; 
    bool lfSubscript_: 1; 
    bool lfSuperscript_: 1; // still 13 bytes 
}; 

który jest następnie wypełnione do 16 bajtów, a po drugie mamy:

struct a { 
    uint32_t foreColor_ : 32; // 4 bytes (total) 
    uint32_t backColor_ : 32; // 8 bytes 
    uint16_t lfHeight_ : 16; // 10 bytes 
    uint8_t  flags_: 4;  // 11 bytes 
    bool lfBold_: 1;   // 12 bytes 
    bool lfItalic_: 1; 
    bool lfUnderLine_: 1; 
    bool lfDashLine_: 1; 
    bool lfStrike_: 1; 
    bool lfSubscript_: 1; 
    bool lfSuperscript_: 1; // still 12 bytes 
}; 

który wymaga żadnej wyściółki i pozostaje na 12 bajtów.

+1

Jest to implementacja zdefiniowana, bez wątpienia, ale nie mówi wiele za jakość implementacji, gdy jego dwie struktury mają różne rozmiary. –

+0

* wzruszam ramionami * Myślę, że większość implementacji, z którymi współpracowałem, zachowuje się w ten sposób. Połączą się jak pola, ale nie inaczej niż pola. Myślałem, że tak było zdefiniowane w standardzie, dopóki nie sprawdziłem. –

+0

Nie sądzę, że kiedykolwiek widziałem implementację, która działała w ten sposób przedtem. G ++ z pewnością nie. –

0

Jest to specyficzne dla kompilatora, kompilator wykonuje różne linie trasowania w celu optymalizacji dostępu do pól.

Jeśli chcesz (musisz) polegać na wyrównaniu. (jak przetwarzanie nagłówków sieci) Musisz użyć #pragma push, pop.

Lub __ atrybut __ (pakowany) - który jest rozszerzeniem GCC.

struct { 
... 
} __attribute__(packed) 

To zmusi kompilator do zgniecenia.

Powiązane problemy