名稱空間
變體
操作

位域

來自 cppreference.com
< c‎ | language

宣告一個具有顯式位寬的成員。相鄰的位域成員可以打包,共享和跨越單個位元組。

位域宣告是一個 structunion 成員宣告,它使用以下宣告符

identifier (可選) : width
identifier - 正在宣告的位域的名稱。名稱是可選的:無名位域引入指定數量的填充位
width - 一個整數常量表達式,其值大於或等於零,且小於或等於底層型別中的位數。當大於零時,這是此位域將佔用的位數。值零僅允許用於無名位域,並且具有特殊含義:它指定類定義中的下一個位域將從一個分配單元的邊界開始。

目錄

[編輯] 解釋

位域只能具有以下型別之一(可能帶有 constvolatile 限定符)

  • unsigned int,用於無符號位域(例如 unsigned int b : 3; 的範圍是 [07]
  • signed int,用於有符號位域(signed int b : 3; 的範圍是 [-43]
  • int,用於具有實現定義有符號性的位域(請注意,這與關鍵字 int 在其他任何地方的含義不同,其他地方表示“signed int”)。例如,int b : 3; 的值範圍可能是 [07][-43]
  • _Bool,用於單位元位域(例如 bool x : 1;)的範圍是 [01],並且其隱式轉換遵循布林轉換規則。
(C99 起)
  • 位精確整數型別(例如 _BitInt(5) : 4; 的範圍是 [-87],而 unsigned _BitInt(5) : 4; 的範圍是 [015])。
(自 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 起) 一起使用。

[編輯] 注意

以下位域用法會導致未定義行為

位域的以下屬性未指定

  • 包含位域的分配單元的對齊方式。

位域的以下屬性實現定義

  • 型別為 int 的位域是被視為有符號還是無符號。
  • 是否允許除了 intsigned intunsigned 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++ 文件 關於 位域