某些資料在儲存時不需佔用完整位元組,僅需幾個位元即可。例如開關狀態僅需 1 位元。C 語言提供位域機制,允許在結構體中指定成員佔用的位元數。
struct bs {
unsigned m; // 佔 4 位元組
unsigned n : 4; // 佔 4 位元
unsigned char ch : 6; // 佔 6 位元
};
冒號後的數字限定該成員佔用的位元數。未限定者依資料類型決定長度。
位域成員的取值範圍受位元數限制。超出範圍時,高位會被直接截斷:
#include <stdio.h>
int main() {
struct bs {
unsigned m;
unsigned n : 4;
unsigned char ch : 6;
} a = { 0xad, 0xE, '$' };
printf("%#x, %#x, %c\n", a.m, a.n, a.ch); // 0xad, 0xe, $
a.m = 0xb8901c;
a.n = 0x2d; // 二進位 10 1101 → 截斷為 1101 (0xd)
a.ch = 'z'; // ASCII 0x7a → 二進位 111 1010 → 截斷為 11 1010 (0x3a ':')
printf("%#x, %#x, %c\n", a.m, a.n, a.ch); // 0xb8901c, 0xd, :
return 0;
}
unsigned int 為 32 位,unsigned char 為 8 位)。int、signed int、unsigned int;C99 新增 _Bool。但主流編譯器擴展支援 char、enum 等類型。C 標準未強制規定配置細節,編譯器盡量壓縮空間。主要規則如下:
struct bs {
unsigned m : 6;
unsigned n : 12;
unsigned p : 4;
}; // 總位寬 22 < 32,sizeof = 4 位元組
若將 m 改為 22 位,總和 34 > 32,n 另起爐灶,sizeof = 8。
若成員間穿插一般變數,不進行壓縮,各編譯器行為一致。
struct bs {
int m : 12;
int : 20; // 無名位域,用於填充
int n : 4;
};
無名位域不可存取,常用於調整後續成員位置或強制對齊。上例中若無 20 位填充,sizeof = 4;有填充則 sizeof = 8。
位域成員不佔用完整位元組,且可能不在位元組邊界,因此不能取址(&),C 語言明確禁止對位域成員使用取址運算子。