簡體   English   中英

編譯器如何確定位域結構的大小?

[英]How does compiler determine the size of a bitfield struct?

例如:

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

是16個字節但是

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

是12個字節長。

我認為flags_應該有相同的長度,但似乎沒有。

為什么?

標准( 工作草案的 9.6)說:

指定一個位域; 它的長度是通過冒號從位字段名稱中設置的。 bit-field屬性不是類成員類型的一部分。 常量表達式應為具有大於或等於零的值的整數常量表達式。 常量表達式可能大於位域類型的對象表示(3.9)中的位數; 在這種情況下,額外的比特用作填充比特,並且不參與比特字段的值表示(3.9)。 類對象中位域的分配是實現定義的。 位字段的對齊是實現定義的 比特字段被打包到一些可尋址的分配單元中。 [注意:位字段跨越某些機器上的分配單元而不是其他機器上的分配單元。 在某些機器上從右到左分配位字段,在其他機器上從左到右分配。 - 尾注]

(我的重點)

所以這取決於你的編譯器。 在您的情況下似乎正在發生的事情 - 我將其描述為相當正常的行為 - 是它只是組合相同類型的位域然后將結構打包到4字節邊界,所以在第一種情況下我們有:

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

然后填充到16個字節,在第二個字節中我們有:

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

它不需要填充,並保持12個字節。

它是特定於編譯器的,編譯器正在進行各種對齊以優化對字段的訪問。

如果你想(需要)依賴於對方。 (比如網絡頭處理)你需要使用#pragma push,pop。

或者__ attribute __(packed) - 這是一個GCC擴展。

struct {
...
} __attribute__(packed)

這將迫使編譯器壓縮它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM