共用體(Union)是 C 語言特有的資料結構,允許不同型別的成員共享同一塊記憶體空間。任一時刻僅有一個成員持有有效值,大小等於最大成員的大小。廣泛應用於型別轉換、硬體暫存器存取、資料序列化、節省記憶體等場景。本文詳細說明定義、存取規則、記憶體模型、常見陷阱與實務範例。
union [標籤] {
成員定義;
成員定義;
...
} [變數列表];
範例:定義可儲存整數、浮點數或字串的 Data 型別:
union Data {
int i;
float f;
char str[20];
} data;
data 佔用 20 位元組(str[20] 最大)。
#include <stdio.h>
#include <string.h>
union Data { int i; float f; char str[20]; };
int main() {
union Data data;
printf("Memory size occupied by data : %zu\n", sizeof(data));
return 0;
}
輸出:
Memory size occupied by data : 20
使用成員存取運算子 .(或指標用 ->)。關鍵特性:寫入一個成員會覆蓋其他成員的位元模式。
union Data data;
data.i = 10;
data.f = 220.5;
strcpy(data.str, "C Programming");
printf("data.i : %d\n", data.i); // 1917853763 (垃圾值)
printf("data.f : %f\n", data.f); // 4122360580327794860452759994368.000000 (垃圾值)
printf("data.str : %s\n", data.str); // C Programming (正確,最後寫入)
只有最後寫入的 str 保持有效,前兩者因位元模式被覆蓋而成為無意義值。
union Data data;
data.i = 10;
printf("data.i : %d\n", data.i); // 10
data.f = 220.5;
printf("data.f : %f\n", data.f); // 220.500000
strcpy(data.str, "C Programming");
printf("data.str : %s\n", data.str); // C Programming
每次僅讀取最近寫入的成員,所有輸出皆正確。
共用體是合法的型別雙關,可用於檢視浮點數位元模式、整數位元組分解等:
union FloatBits {
float f;
unsigned int bits;
};
void print_float_bits(float val) {
union FloatBits fb;
fb.f = val;
printf("Value: %f, Hex: 0x%08X\n", fb.f, fb.bits);
// 進一步解析:sign = bits>>31, exp = (bits>>23)&0xFF, mantissa = bits&0x7FFFFF
}
union EndianTest {
uint32_t i;
uint8_t c[4];
};
bool is_little_endian() {
union EndianTest test;
test.i = 0x01020304;
return test.c[0] == 0x04; // 低位元組在低位址
}
結構體中可嵌入無標籤共用體,成員直接提升至結構體作用域:
struct Packet {
uint16_t header;
union {
struct { uint8_t cmd; uint8_t len; } control;
struct { uint32_t addr; uint16_t port; } data;
};
uint16_t crc;
};
// 存取:pkt.cmd, pkt.addr 等,無需 pkt.u.cmd
| 陷阱 | 說明 | 對策 |
|---|---|---|
| 讀取非作用中成員 | 行為未定義(C 標準),產生垃圾值 | 嚴格遵守「寫入後立即讀取同一成員」 |
| 對齊需求差異 | 成員對齊要求可能導致共用體大小大於最大成員 | 使用 alignas (C11) 或編譯器屬性控制對齊 |
| 跨平台資料交換 | 位元組序、填充、大小皆可能不同 | 序列化時明確處理端序,避免直接傳輸共用體 |
| 嚴格別名規則違反 | 透過共用體進行型別雙關在 C99/C11 為合法,但 C++ 不同 | C 程式碼中合法使用;混合 C/C++ 專案需謹慎 |
| 特性 | 結構體 | 共用體 |
|---|---|---|
| 記憶體配置 | 成員依序排列,大小為總和(含填充) | 成員重疊共享,大小為最大成員 |
| 同時有效成員 | 所有成員 | 僅一個 |
| 典型用途 | 資料聚合、記錄表示 | 型別轉換、互斥資料、記憶體節省 |
共用體是 C 語言底層記憶體操作的核心工具,提供型別重疊與記憶體共享能力。正確使用需遵守「單一作用成員」原則,並深度理解目標平台記憶體模型。在嵌入式開發、系統程式、高效能序列化等領域,共用體是不可或缺的進階技術。