位域
來自 cppreference.com
宣告一個具有顯式位寬的成員。相鄰的位域成員可以打包,共享和跨越單個位元組。
位域宣告是一個 struct 或 union 成員宣告,它使用以下宣告符
identifier (可選) : width |
|||||||||
identifier | - | 正在宣告的位域的名稱。名稱是可選的:無名位域引入指定數量的填充位 |
width | - | 一個整數常量表達式,其值大於或等於零,且小於或等於底層型別中的位數。當大於零時,這是此位域將佔用的位數。值零僅允許用於無名位域,並且具有特殊含義:它指定類定義中的下一個位域將從一個分配單元的邊界開始。 |
目錄 |
[編輯] 解釋
位域只能具有以下型別之一(可能帶有 const 或 volatile 限定符)
- unsigned int,用於無符號位域(例如 unsigned int b : 3; 的範圍是
[
0,
7]
) - signed int,用於有符號位域(signed int b : 3; 的範圍是
[
-4,
3]
) - int,用於具有實現定義有符號性的位域(請注意,這與關鍵字 int 在其他任何地方的含義不同,其他地方表示“signed int”)。例如,int b : 3; 的值範圍可能是
[
0,
7]
或[
-4,
3]
。
|
(C99 起) |
|
(自 C23 起) |
其他實現定義的型別可能被接受。位域是否可以具有原子型別也是實現定義的。(C11 起) 位域中的位數(width)設定了它可以容納的值的範圍限制
執行此程式碼
#include <stdio.h> struct S { // three-bit unsigned field, // allowed values are 0...7 unsigned int b : 3; }; int main(void) { struct S s = {7}; ++s.b; // unsigned overflow printf("%d\n", s.b); // output: 0 }
允許(並且通常會)將多個相鄰位域打包在一起
執行此程式碼
#include <stdio.h> struct S { // will usually occupy 4 bytes: // 5 bits: value of b1 // 11 bits: unused // 6 bits: value of b2 // 2 bits: value of b3 // 8 bits: unused unsigned b1 : 5, : 11, b2 : 6, b3 : 2; }; int main(void) { printf("%zu\n", sizeof(struct S)); // usually prints 4 }
寬度為零的特殊“無名位域”用於打破填充:它指定下一個位域從下一個分配單元的開頭開始。
執行此程式碼
#include <stdio.h> struct S { // will usually occupy 8 bytes: // 5 bits: value of b1 // 27 bits: unused // 6 bits: value of b2 // 15 bits: value of b3 // 11 bits: unused unsigned b1 : 5; unsigned : 0; // starts a new unsigned int unsigned b2 : 6; unsigned b3 : 15; }; int main(void) { printf("%zu\n", sizeof(struct S)); // usually prints 8 }
由於位域不一定從位元組的開頭開始,因此不能獲取位域的地址。不支援指向位域的指標。位域不能與 sizeof
和 _Alignas
(C11 起)(C23 前)alignas
(C23 起)(C11 起) 一起使用。
[編輯] 注意
以下位域用法會導致未定義行為
- 對位域呼叫 offsetof。
位域的以下屬性未指定
- 包含位域的分配單元的對齊方式。
位域的以下屬性實現定義
- 型別為 int 的位域是被視為有符號還是無符號。
- 是否允許除了 int、signed int、unsigned int、_Bool(C99 起),以及(可能為 unsigned)_BitInt(N)(C23 起) 之外的型別。
|
(C11 起) |
- 位域是否可以跨越分配單元邊界。
- 位域在分配單元內的順序(在某些平臺上,位域從左到右打包,在其他平臺上從右到左)。
儘管 _Bool 的物件表示中的位數至少為 CHAR_BIT,但型別為 _Bool 的位域的 width 不能大於 1。 |
(C99 起) |
在 C++ 程式語言中,位域的寬度可以超過底層型別的寬度(但額外的位是填充位),並且型別為 int 的位域始終是有符號的。
[編輯] 參考
- C23 標準 (ISO/IEC 9899:2024)
- 6.7.2.1 結構體和聯合體說明符
- C17 標準 (ISO/IEC 9899:2018)
- 6.7.2.1 結構體和聯合體說明符
- C11 標準 (ISO/IEC 9899:2011)
- 6.7.2.1 結構體和聯合體說明符
- C99 標準 (ISO/IEC 9899:1999)
- 6.7.2.1 結構體和聯合體說明符
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.5.2.1 結構體和聯合說明符
[編輯] 另見
C++ 文件 關於 位域
|