位域允許在結構體成員中指定佔用的位數,適用於旗標集合、硬體暫存器映射、通訊協定解析等場景。
struct BitField {
unsigned int flag1 : 1; // 1 位
unsigned int flag2 : 1;
unsigned int value : 6; // 6 位 (0-63)
unsigned int : 0; // 強制對齊到下一個 int 邊界
unsigned int flag3 : 1;
};
unsigned int : 3; 僅作填充/對齊,不可存取unsigned int : 0; 強制下一成員對齊到新單元struct Status {
unsigned int mode : 2; // bit 0-1
unsigned int fan : 2; // bit 2-3
unsigned int swing : 1; // bit 4
unsigned int : 3; // bit 5-7 (填充)
unsigned int temp : 8; // bit 8-15 (下一個 byte)
unsigned int : 0; // 強制對齊到下一個 int (bit 32)
unsigned int err : 4; // bit 32-35
};
// 總大小:8 bytes (2 個 int)
struct Status s; s.mode = 2; // 直接賦值,編譯器自動處理位移/遮罩 s.fan = 3; s.swing = 1; // 整數與位域互轉 (需相同大小) uint8_t byte = 0x6A; // 0110 1010 struct Status *ps = (struct Status*)&byte; // ps->mode = 2 (bit 0-1: 10) // ps->fan = 2 (bit 2-3: 10) // ps->swing= 0 (bit 4: 0) // 填充位 = 011 (bit 5-7)
| 限制 | 說明 | 對策 |
|---|---|---|
| 不可取址 | &s.mode 非法 | 用整數暫存變數中轉 |
| 不可建立陣列 | struct { int a:1; } arr[10]; 非法 | 用整數陣列 + 位運算 |
| 跨平台不可移植 | 位序、對齊、填充順序由實作定義 | 協定解析用手動位運算 |
| 有號位域陷阱 | int a:3; 範圍 -4~3 而非 0~7 | 統一用 unsigned |
| sizeof 不可用於位域 | sizeof(s.mode) 非法 | 用 sizeof(s) |
// UART 控制暫存器
struct UART_CTRL {
unsigned int en : 1; // 啟用
unsigned int tx_en : 1; // 發送啟用
unsigned int rx_en : 1; // 接收啟用
unsigned int parity: 2; // 0=無, 1=奇, 2=偶
unsigned int stop : 1; // 停止位
unsigned int : 2; // 保留
unsigned int baud : 8; // 波特率分頻
};
// 寫入暫存器
volatile struct UART_CTRL *uart = (void*)0x40004000;
uart->en = 1;
uart->baud = 0x68; // 9600 @ 16MHz
struct PacketHeader {
uint8_t sync : 2; // 同步碼
uint8_t ver : 3; // 版本
uint8_t type : 3; // 封包類型
uint16_t len : 10; // 長度
uint16_t : 6; // 保留
uint16_t crc : 10; // CRC
uint16_t : 6; // 保留
};
// 注意:跨平台解析建議用手動位運算
struct FileFlags {
unsigned int readonly : 1;
unsigned int hidden : 1;
unsigned int system : 1;
unsigned int archive : 1;
unsigned int compressed: 1;
unsigned int encrypted : 1;
unsigned int : 2; // 保留
};
// 1 byte 儲存 6 個旗標,比 6 個 bool 省 5 bytes
int,但可用 char/short/long 指定:0 強制對齊需跨平台、可維護、型別安全時,建議使用:
GET_BIT(reg, 3), SET_BIT(reg, 3, val) 宏static_assert(sizeof(Reg) == 4) 確保佈局