位域允許在結構體中按位劃分成員,節省記憶體。成員類型限定為 `int`/`unsigned int`/`signed int`(C99 增加 `_Bool`,編譯器常擴展支援其他整型)。
struct bs {
int a : 8; // 佔 8 位
int b : 2; // 佔 2 位
int c : 6; // 佔 6 位
}; // 共 16 位 = 2 字節
struct {
unsigned a : 4;
unsigned : 0; // 無名位域,寬度 0 → 強制從下一存儲單元開始
unsigned b : 4; // 從新字節/字開始
unsigned c : 4;
};
`int` 通常 32 位,位域最大 `:32`;`char` 8 位,最大 `:8`。
struct {
int a : 1;
int : 2; // 2 位填充,不可用
int b : 3;
};
struct foo2 { char a:2; char b:3; char c:1; }; // 共 6 位 < 8 位 → sizeof = 1
struct foo3 { char a:2; char b:3; char c:7; }; // 共 12 位 > 8 位 → a,b 打包 1 字節,c 獨佔 1 字節 → sizeof = 2
struct foo4 { char a:2; char b:3; int c:1; };
// GCC: a,b 打包 1 字節,c 獨立 4 字節對齊 → 中間 3 字節填充 → sizeof = 8
// MSVC: 全部按 int(4) 對齊 → sizeof = 8
struct s1 { int i:8; int j:4; int a:3; double b; }; // i,j,a 共 15 位 < 32 → 打包 4 字節,b 8 字節對齊 → 共 16
struct s2 { int i:8; int j:4; double b; int a:3; }; // i,j 12 位 → 4 字節,b 8 字節,a 獨立 4 字節 → 共 24
typedef struct {
uint32_t enable : 1;
uint32_t mode : 2;
uint32_t reserved : 13;
uint32_t threshold : 16;
} CtrlReg;
// 寫入整個暖存器
*((volatile uint32_t *)0x40001000) = *(uint32_t *)&ctrl_reg;
// IPv4 頭部片段(大端序需注意位序)
struct ipv4_hdr {
uint8_t version : 4;
uint8_t ihl : 4;
uint8_t dscp : 6;
uint8_t ecn : 2;
uint16_t total_len;
// ...
} __attribute__((packed));
struct FileFlags {
unsigned readable : 1;
unsigned writable : 1;
unsigned executable : 1;
unsigned hidden : 1;
unsigned system : 1;
unsigned archive : 1;
unsigned reserved : 2;
};
// 獲取第 n 位 (0-index) #define GET_BIT(val, n) (((val) >> (n)) & 1) // 設置第 n 位 #define SET_BIT(val, n) ((val) |= (1 << (n))) // 清除第 n 位 #define CLR_BIT(val, n) ((val) &= ~(1 << (n))) // 翻轉第 n 位 #define FLIP_BIT(val, n) ((val) ^= (1 << (n)))
優點:行為標準化、跨平台一致、無對齊驚喜、可用於任意整型變量。缺點:語法稍繁瑣,可封裝為 inline 函數。
位域是 C 語言節省記憶體的利器,但在跨平台佈局、有號陷阱、取址限制上暗藏坑點。嵌入式暖存器映射、協議解析等對佈局強依賴場景,**建議改用標準位運算**;一般業務標誌位集合、內部壓縮存儲可放心使用位域,並配合靜態斷言驗證 `sizeof` 符合預期。