struct BitField {
unsigned int a : 1; // 1 位:0~1
unsigned int b : 2; // 2 位:0~3
unsigned int c : 3; // 3 位:0~7
unsigned int d : 4; // 4 位:0~15
// 總計 10 位,通常佔 2 字節 (視對齊)
};
#include
struct Flags {
unsigned int f1 : 1;
unsigned int f2 : 2;
unsigned int f3 : 3;
unsigned int f4 : 4;
};
int main() {
struct Flags f = {0};
f.f1 = 1; // OK
f.f2 = 3; // OK (max 3)
f.f3 = 7; // OK (max 7)
f.f4 = 15; // OK (max 15)
// f.f4 = 16; // 警告/截斷:超出 4 位範圍,實際存 0
printf("f1=%u, f2=%u, f3=%u, f4=%u\n", f.f1, f.f2, f.f3, f.f4);
printf("Size: %zu bytes\n", sizeof(struct Flags)); // 通常 4 或 2
return 0;
}
#include
#include
// 小端序 (x86/ARM) 佈局:b1 佔最低位 (bit 0), b8 佔最高位 (bit 7)
struct ByteBits_LE {
uint8_t b1 : 1; // Bit 0 (LSB)
uint8_t b2 : 1;
uint8_t b3 : 1;
uint8_t b4 : 1;
uint8_t b5 : 1;
uint8_t b6 : 1;
uint8_t b7 : 1;
uint8_t b8 : 1; // Bit 7 (MSB)
} __attribute__((packed)); // GCC/Clang 強制緊湊 1 字節
int main() {
struct ByteBits_LE bb = {0};
uint8_t *p = (uint8_t*)&bb; // 類型雙關 (僅限此處安全)
bb.b1=1; bb.b2=1; bb.b3=1; bb.b4=1; bb.b5=1; bb.b6=1; bb.b7=1; bb.b8=1;
printf("全 1: %u (預期 255)\n", *p);
bb.b1=1; bb.b2=0; bb.b3=0; bb.b4=0; bb.b5=0; bb.b6=0; bb.b7=0; bb.b8=0;
printf("00000001: %u (預期 1)\n", *p); // 小端序:b1=LSB
bb.b1=0; bb.b2=0; bb.b3=0; bb.b4=0; bb.b5=1; bb.b6=1; bb.b7=1; bb.b8=1;
printf("11110000: %u (預期 240? 不,小端序 b5-b8 是高位) -> 實際: %u\n", *p);
// 注意:位域佈局端序相關,網路/檔案格式**禁止**直接用位域結構體映射!
return 0;
}
警告:上述輸出在大端序機器 (如 PowerPC, s390x) 完全不同。**跨平台二進制協議請用位運算 (`>>`, `<<`, `&`, `|`) 手動打包/解包**。
struct Mixed {
unsigned int flag : 1;
unsigned int mode : 2;
float value; // 4 字節,會觸發對齊填充
double precision; // 8 字節
};
// 記憶體佈局 (典型 64 位系統):
// offset 0: flag(1), mode(2), padding(5 bits? 實際通常對齊到 4 字節邊界)
// offset 4: value (float)
// offset 8: padding (4 bytes) -> offset 16: precision (double)
// sizeof 可能為 24 或 32 字節
**不要**直接用位域結構體映射暫存器 (佈局不確定)。**標準做法**:定義位遷移宏或內聯函數。
// 定義暫存器位遷移常數
#define REG_CTRL_ENABLE_BIT (0)
#define REG_CTRL_MODE_MASK (0x3 << 1) // Bit 1-2
#define REG_CTRL_IRQ_EN_BIT (3)
// 讀寫輔助宏
#define READ_REG(addr) (*(volatile uint32_t*)(addr))
#define WRITE_REG(addr, val) (*(volatile uint32_t*)(addr) = (val))
// 位操作封裝
static inline void set_enable(uint32_t addr, bool en) {
uint32_t v = READ_REG(addr);
v = en ? (v | (1<
此法**保證跨編譯器/架構行為一致**,且編譯器優化極好 (常數傳播)。
位域是 C 語言**最不具可移植性**的特性之一。理解其「僅為編譯器提示、佈局未標準化、無法取址」的本質。**嵌入式暫存器操作請用位運算宏/內聯函數**;一般應用層壓縮旗標可用 `std::bitset` (C++) 或手動位掩碼操作 `uint32_t`/`uint64_t`,效果更可控。