為何選擇「聯合體+位域」?
- 同時支援整字節讀寫(
uFg1)與單一位操作(F_10MS)
- 節省 RAM:8 個標志位僅佔 1 位元組
- 編譯器生成位操作指令(
BSET/BCLR),執行極快
標準定義範本
typedef union {
uint8_t Flg; // 整字節訪問
struct {
uint8_t Flg1 : 1; // 位域:1 位元組
uint8_t Flg2 : 1;
uint8_t Flg3 : 1;
uint8_t Flg4 : 1;
uint8_t Flg5 : 1;
uint8_t Flg6 : 1;
uint8_t Flg7 : 1;
uint8_t Flg8 : 1;
} tFlg;
} uFLG;
uFLG uF1, uF2;
// 宏定義簡化調用
#define uFg1 uF1.Flg
#define F_10MS uF1.tFlg.Flg1
#define F_Fls1s uF1.tFlg.Flg2
// ...
實戰應用模式
void main(void) {
while (1) {
// 等待 10ms 中斷標志(中斷中置 1)
while (!F_10MS);
F_10MS = 0; // 清標志
CmdKey(); // 10ms 週期任務
CmdDisplay();
uFg2 = 0; // 整字節清零(批量復位 LED 標志)
F_LED1 = 1; // 單獨置位 LED1 標志
}
}
避坑指南
- 位域順序:C 標準未規定分配順序(高位在前/低位在前),跨平台移植時需驗證或改用手動位掩碼
- 原子性:單位元組讀寫通常原子,但「讀-改-寫」非原子,中斷/多任務環境需關中斷或用原子指令
- 類型寬度:位域基礎類型建議用
unsigned int 或 uint8_t,避免有號擴展問題
- 對齊:部分編譯器要求位域不跨越字邊界,大量位域時注意結構體大小
擴展:手動位掩碼替代方案
// 同樣效果,無移植性疑慮
#define SET_BIT(reg, bit) ((reg) |= (1 << (bit)))
#define CLR_BIT(reg, bit) ((reg) &= ~(1 << (bit)))
#define GET_BIT(reg, bit) ((reg) & (1 << (bit)))