共用体(union,亦称共同体)的语法形式与结构体相近,但内存布局不同:结构体各成员占用各自的存储;共用体的所有成员共享同一段存储,共用体的大小一般等于最大成员的大小(可能含对齐填充)。在实际开发中,共用体多用于在几种互斥数据之间复用同一块内存以节省空间(例如带类型标记的变体字段),或与协议报文、硬件寄存器等需要“同一地址按不同类型解读”的场景;使用时须由程序逻辑保证当前访问的成员与真实数据含义一致。
共用体的基本行为
对某一成员赋值后,其他成员原先的内容会被覆盖;同一时刻通常只应把其中一个成员视为有效。访问成员仍使用点运算符 .。
#include <stdio.h>
union Student {
int rollNo;
float height;
char firstLetter;
};
int main(void) {
union Student data;
data.rollNo = 21;
printf("%d\n", data.rollNo);
data.height = 5.2f;
printf("%.2f\n", data.height); /* rollNo 的内容已被覆盖 */
data.firstLetter = 'N';
printf("%c\n", data.firstLetter);
return 0;
}结构体成员各占独立空间;共用体成员映射到同一块内存,同时仅一个成员语义有效。
共用体的大小
union A {
int x;
char y;
};
union B {
int arr[10];
char y;
};
printf("Sizeof A: %zu\n", sizeof(union A));
printf("Sizeof B: %zu\n", sizeof(union B));较小成员可存放在为最大成员预留的空间内,不会单独再占一份与最大成员等大的区域。
示例:按字节查看整数
union intParts {
int theInt;
char bytes[sizeof(int)];
};
union intParts parts;
parts.theInt = 5968145;
printf("整数是 %d\n", parts.theInt);
printf("四个字节分别是 [%d, %d, %d, %d]\n",
parts.bytes[0], parts.bytes[1],
parts.bytes[2], parts.bytes[3]);共用体为同一存储提供了多种“视图”,避免手动进行指针类型转换。
节省空间:带类型标识的共用体
若某对象在逻辑上只可能是整数或浮点数之一,用结构体同时保存所有候选成员会浪费空间。可在外层保存类型标识,在共用体中只保留一种有效表示:
struct operator {
int type;
union {
int intNum;
float floatNum;
double doubleNum;
} types;
};struct operator op;
op.type = 0;
op.types.intNum = 352;若共用体未命名(匿名共用体),其成员可直接作为外层结构体的成员访问:
struct operator {
int type;
union {
int intNum;
float floatNum;
double doubleNum;
};
};
op.type = 0;
op.intNum = 352;命名成员与数组视图
可将具名成员与数组放在同一共用体中,以便既按名称访问又按下标遍历(布局依赖成员声明顺序与对齐):
union Coins {
struct {
int quarter;
int dime;
int nickel;
int penny;
};
int coins[4];
};
union Coins change;
for (int i = 0; i < 4; i++) {
change.coins[i] = i * 10;
}
printf("quarter=%d dime=%d nickel=%d penny=%d\n",
change.quarter, change.dime, change.nickel, change.penny);适用场合
- 在多种互斥表示之间复用同一块存储以节省内存。
- 与硬件寄存器、协议字段等“同一地址多种解释”的场景对应。
- 配合类型字段,表示“当前有效的是哪一种成员”。
结构体便于同时保存全部成员;共用体节省空间,但须由程序逻辑保证访问的成员与当前数据含义一致。