簡體   English   中英

為什么結構大小隨結構中的枚舉位域而變化(標准C)

[英]Why does struct size change with enum bitfield in struct (standard C)

使用這個問題中提供的代碼,我觀察到當使用 8 位寬的枚舉而不是uint8_t類型時,結構的大小會增加。

請查看以下代碼示例:

代碼選項 A

typedef enum { A, B, C, MAX = 0xFF } my_enum;

struct my_compact_struct_option_a
{
    my_enum field1 : 8; // limiting enum size to 8 bits 
    uint8_t second_element[6];
    uint16_t third_element;
};

此結構second_element中第二個變量的偏移量為 1。這表明枚舉字段 1 的大小限制為 uint8_t field1 但是,結構的大小是 12 個字節。 這對我來說是出乎意料的。

將此與

代碼選項 B

typedef uint8_t my_type;

struct my_compact_struct_option_b
{
    my_type field1; 
    uint8_t second_element[6];
    uint16_t third_element;
};

這里, second_element的偏移量也是 1,但是這個結構的大小是 10 字節。 這是預期的。

為什么第一個代碼示例中的結構增加到 12 個字節?

您可以隨時親自嘗試此代碼

C 標准未指定位字段的對齊要求,因此它是(隱式)實現定義的。 從這個C17 標准草案(我的粗體強調):

6.7.2.1 結構和聯合說明符


11 實現可以分配任何大到足以容納位字段的可尋址存儲單元 如果有足夠的空間剩余,緊跟在結構中另一個位域之后的位域將被打包到同一單元的相鄰位中。 如果剩余空間不足,則將不適合的位域放入下一個單元還是與相鄰單元重疊是實現定義的。 單元內位域的分配順序(高位到低位或低位到高位)是實現定義的。 未指定可尋址存儲單元的對齊方式。

因此,雖然該段規定(例如)進一步添加my_enum field2 : 8; 應該“打包”到與field1相同的存儲單元中(假設仍有足夠的空間), 2它允許編譯器自由決定他們認為該存儲單元的最佳對齊要求(和大小)。

似乎大多數編譯器(來自Compiler Explorer上可用的編譯器)選擇將“基本”類型的對齊要求強加於位字段。 1此外,由於 C 中的enum具有(固定的)基礎類型int ,這意味着您的field1 (因此,您的my_compact_struct_option_a )具有“int”的對齊要求 - 在許多 / 上可能是 4 個字節大多數系統。


1當您考慮如何實現對位域的訪問時,這是有道理的:如果要將其“用作” int ,則需要將其作為int進行訪問

2例如,在field1之后立即向結構中添加更多位域成員不會增加結構的整體大小,直到這些添加的位域的總大小超過 24 位。

如另一個答案中所述,C 標准規定實現可以使用任何足夠大的存儲單元來保存位域。 由於默認情況下enum實際上是int ,因此大多數編譯器將使用int大小的存儲單元作為位域。 特別是,gcc 和 MSVC 都將創建一個 4 字節的enum和一個 12 字節的struct

在評論中指定的情況下:

 struct foo { int a : 8; char b; };

gcc 和 clang 的大小為 4,而 MSVC 的大小為 8。

所以似乎正在發生的是a駐留在一個int大小的存儲單元中,因為這是位域的基本類型。 結構的 alignment 是 4,因為這是最大字段的大小,特別是保存位域的int大小的單元。

Where gcc and clang seem to differ from MSVC is that gcc and clang will allow non-bitfields to occupy the same storage unit as bitfields if there is sufficient space to do so, while MSVC keeps bitfields in their own storage units.


如果您想使enum類型更小,則可以使用特定於實現的方法來執行此操作。

在 gcc 中,可以使用packed屬性:

typedef enum __attribute__((__packed__)) { A, B, C, MAX = 0xFF } my_enum;

或者您可以通過-fshort-enums標志來縮小所有枚舉的大小。 兩者都會使my_enum的大小為 1 個字節,而struct my_compact_struct_option_a的大小為 10 個字節。

clang 允許您使用以下語法指定枚舉的大小:

typedef enum : char { A, B, C, MAX = 0xFF } my_enum;

暫無
暫無

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

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