union 本質:多變量共享同一塊內存
- 大小 = 最大成員大小 (按最大對齊對齊)。
- 同一時刻**只能存儲一個成員**的值,寫入新成員會覆蓋舊值。
- 適用場景:節省內存、類型懲罰、協議解析、硬件寄存器映射。
語法與基本示例
union Data {
int i;
float f;
char c[4];
};
union Data d;
d.i = 0x41424344; // 写入整數
printf("i=0x%X, f=%f, c=%s\n", d.i, d.f, d.c);
// 輸出取決於端序:小端機 c="DCBA", f≈1.23e-10 (非預期值,演示覆蓋)
經典應用 1:節省內存 - 教師/學生通用表
struct Person {
char name[20];
int age;
char type; // 'T' 教師, 'S' 學生
union {
char dept[20]; // 教師:教研室
int grade; // 學生:年級
} info;
};
// 結構體大小 = 20+4+1+max(20,4) + 對齊 ≈ 48 字節
// 若分開定義兩結構體數組,總內存翻倍
經典應用 2:類型懲罰 - 無需序列化庫的浮點/整數位模式互查
union FloatInt {
float f;
uint32_t u;
};
float f = 3.14159f;
union FloatInt fi = {.f = f};
printf("Float %f = 0x%08X (IEEE 754)\n", f, fi.u);
// 輸出: Float 3.141590 = 0x40490FDB
經典應用 3:網絡協議/文件格式解析 - 同一字節流多視圖
#pragma pack(1)
union Packet {
uint8_t raw[12];
struct {
uint16_t magic; // 0xA5A5
uint8_t version;
uint8_t type;
uint32_t seq;
uint32_t crc;
} fields;
};
#pragma pack()
// 接收網絡數據
union Packet pkt;
recv(sock, pkt.raw, sizeof(pkt), 0);
// 直接訪問結構化字段
if (pkt.fields.magic == 0xA5A5) process(pkt.fields.type, pkt.fields.seq);
經典應用 4:硬件寄存器位域映射
union GPIO_REG {
uint32_t word;
struct {
uint32_t MODE0 : 2;
uint32_t MODE1 : 2;
uint32_t MODE2 : 2;
// ...
uint32_t RESERVED : 18;
} bits;
};
volatile union GPIO_REG *gpio = (void*)0x40020000;
gpio->bits.MODE0 = 1; // 設置腳 0 為輸出
// 編譯器自動生成 讀-修改-寫 指令序列
關鍵注意事項
| 陷阱 | 說明 | 對策 |
| 嚴格別名規則違反 | 通過 union 讀取非最近寫入的成員屬實現定義行為 (C99 明確允許),但 C++ 不允許 | C 中放心用;C++ 用 memcpy 或 std::bit_cast (C++20) |
| 端序依賴 | 多字節成員 (int/float) 字節序與 CPU 一致,跨平台傳輸需統一網絡序 | 收發端統一用 htonl/ntohl 或手動字節序轉換 |
| 對齊導致大小超預期 | union 大小按最大成員對齊,可能大於最大成員 | #pragma pack(1) 或 __attribute__((packed)) 壓緊 |
| 未初始化讀取 | 讀取從未寫入的成員 → 不確定值 | 始終先寫入再讀取,或靜態初始化 union U u = {0}; |
union vs struct 對比
struct S { int a; char b; }; // 大小 = 8 (對齊), 同時存 a 和 b
union U { int a; char b; }; // 大小 = 4, 同一時間只存 a 或 b
靈活運用 union,能在嵌入式、系統編程、高性能序列化中實現**零拷貝類型轉換**與**極致內存效率**。
- 上一篇文章: 十天入門單片機 C 語言編程:從 MAIN 函數到項目實戰學習路徑
- 下一篇文章: C語言入門知識體系清單:從語法到工程實踐的完整地圖
Copyright ©
程式碼之家 All Rights Reserved