| 特性 | 結構體 | 聯合體 |
|---|---|---|
| 記憶體分配 | 各成員各自擁有空間,總大小 = 成員大小之和(含對齊填充) | 所有成員共享同一塊記憶體,大尺寸 = 最大成員大小(對齊後) |
| 同時存在性 | 所有成員同時存在 | 同一時刻僅能持有一個成員的值 |
| 賦值行為 | 可同時對多成員賦值 | 新賦值會覆蓋舊值 |
| 初始化 | 可初始化多成員 | C 標準僅允許初始化第一個成員(C99 指定初始化器可指定任一) |
union 聯合體名 {
成員型別 成員名;
...
};
union PerData {
int class; // 學生:班級編號
char office[10]; // 教師:教研室名稱
};
// 1. 先定義後宣告
union PerData { int class; char office[10]; };
union PerData a, b;
// 2. 定義同時宣告
union PerData {
int class;
char office[10];
} a, b;
// 3. 匿名聯合體直接宣告
union {
int class;
char office[10];
} a, b;
union PerData { int class; char office[10]; }; // 假設 int 4 bytes
變數 a:
+------------------+
| office[0..9] | 10 bytes (最大成員)
+------------------+
| class (前 4 bytes 重疊) |
+------------------+
sizeof(union PerData) = 10 (對齊後可能為 12)
- 賦值 a.class = 5 時,僅使用前 4 bytes
- 賦值 strcpy(a.office, "CSIE") 時,使用全部 10 bytes
union PerData data;
data.class = 3; // 整數賦值
data.office[0] = 'A'; // 字元陣列賦值(覆蓋 class)
// 透過指標存取
union PerData *p = &data;
p->class = 4;
strcpy(p->office, "Math");
注意:聯合體變數本身不可直接賦值或比較,必須透過具體成員。
#include <stdio.h>
#include <string.h>
struct Person {
char name[10];
int age;
char job; // 's' = 學生, 't' = 教師
union {
int class;
char office[10];
} dept;
};
int main(void)
{
struct Person list[2];
for (int i = 0; i < 2; i++) {
printf("輸入姓名 年齡 職業(s/t) 部門: ");
scanf("%9s %d %c", list[i].name, &list[i].age, &list[i].job);
if (list[i].job == 's')
scanf("%d", &list[i].dept.class);
else
scanf("%9s", list[i].dept.office);
}
printf("%-10s %3s %3s %s\n", "Name", "Age", "Job", "Dept");
for (int i = 0; i < 2; i++) {
if (list[i].job == 's')
printf("%-10s %3d %3c %d\n",
list[i].name, list[i].age, list[i].job, list[i].dept.class);
else
printf("%-10s %3d %3c %s\n",
list[i].name, list[i].age, list[i].job, list[i].dept.office);
}
return 0;
}
dept 是匿名聯合體成員,直接以 list[i].dept.class 存取。scanf 讀取陣列成員(name、office)時不加 &,因陣列名已退化為指標。job 欄位判別當前使用哪個聯合體成員(標籤欄位模式)。union PerData arr[100];union PerData *p = &data;