📄 一句话概括
共用体(union,也叫联合体)和结构体长得几乎一模一样,但内存安排正好相反:结构体的成员是"并排住"(每人一间房,互不干扰);共用体的成员是"挤在同一间房里"(同一块内存,谁写谁占)。所以共用体的大小不是成员相加,而是取最大的那个成员。它只有一个真正的用途:让同一块内存,在不同时刻被当成不同的类型来用。
📝 本节和前面几节的关系
8.1~8.4 讲的是"怎么把几个数据打包在一起同时保存"。这一节讲一个反过来的需求:有些数据永远不可能同时用到,为什么要给它们各分一块空间?共用体就是"分时复用一间房"。它和结构体的对比(并排 vs 重叠)是本节的记忆锚点,也是"内存布局"这条线索(8.1.5 的对齐 → 本节的重叠)的延续。
一、一句话讲清区别
struct S { int i; double d; char c; }; // 结构体:三间房,并排
union U { int i; double d; char c; }; // 共用体:一间房,三个人轮流住
画成图:
结构体 struct S 共用体 union U
┌──────┬──────┬────┐ ┌──────────────┐
│ i │ d │ c │ │ i / d / c │ ← 同一块内存
└──────┴──────┴────┘ └──────────────┘
4字节 8字节 1字节 取最大的那个(8 字节)
总共 24 字节(含对齐) 总共 8 字节
一句话记牢: - 结构体 = 同时都要 → 各分一间(相加) - 共用体 = 只用其中一个 → 挤一间(取最大)
二、什么时候真的需要它
判断标准:这几个数据"会不会同时被用到"?
| 场景 | 该用哪个 | 为什么 |
|---|---|---|
| 学生的姓名 + 年龄 + 成绩 | 结构体 | 三样随时都要看,缺一不可 |
| 一个数据要么是整数、要么是小数、要么是字符(同一时刻只可能是其中一种) | 共用体 | 不可能同时是两种,没必要各分一间 |
| 通讯协议的一个"变长字段":按类型标志决定它是什么 | 共用体 | 每包只可能是其中一种解读 |
| 想省内存的嵌入式设备(内存按字节抠) | 共用体 | 复用同一块空间 |
回到现实的一句话:共用体是"省内存 + 类型转换"的工具。桌面程序里用得不多,但在协议解析、二进制文件读写、嵌入式这三个领域很常见——所以教材要讲,考试要考。
三、一个直观的例子
假设要记录一个职工的"某项数据"——有时是工号(整数)、有时是工资(小数)、有时是级别(字符):
union StaffData {
int id; // 工号
double salary; // 工资
char level; // 级别
};
一条记录只需要 8 字节(最大的 double),而用结构体要 24 字节。而且这三个数据是互斥的——一个职工的数据,同一时刻只会以其中一种形式存在。
四、本节三篇的分工
| 小节 | 内容 |
|---|---|
| 8.5.1 共用体的定义与声明 | 语法(和 struct 几乎一样) |
| 8.5.2 共用体的大小 | 为什么大小是"最大成员"(含实例05) |
| 8.5.3 共用体的特点 | 三条特点 + 与结构体的完整对比 |
五、动手 Demo:先看一眼"同一块内存"
#include <iostream>
using namespace std;
union U {
int i;
char c;
};
int main() {
U u;
u.i = 1000;
cout << "写 i = 1000 后:u.i = " << u.i << endl;
u.c = 'A'; // 往同一块内存的低字节写了 'A'
cout << "写 c = 'A' 后:u.i = " << u.i << "(被搅乱了!)" << endl;
cout << "sizeof(U) = " << sizeof(U) << " 字节(取最大的 int)" << endl;
cout << "u 的地址 = " << &u << endl;
cout << "u.i 的地址 = " << &u.i << "(相同)" << endl;
cout << "u.c 的地址 = " << &u.c << "(还是相同!)" << endl;
return 0;
}
看到什么算成功:
写 i = 1000 后:u.i = 1000
写 c = 'A' 后:u.i = (变成了另一个数,不是 1000)
sizeof(U) = 4 字节(取最大的 int)
u 的地址 = 0x...
u.i 的地址 = 0x...(相同)
u.c 的地址 = 0x...(还是相同!)
最震撼的一行是最后两行:&u.i 和 &u.c 打印出来是同一个地址——这就直接证明了"它们住在同一间房里"。
30 秒实验:把 union 改成 struct,再跑一遍。&u.i 和 &u.c 立刻变成两个不同的地址,而且 u.c = 'A' 再也搅不乱 u.i。一眼看懂"并排"和"重叠"的区别。
六、常见误区
- "共用体就是省内存的结构体"——只说对了一半。它不只是"省",而是语义完全不同:共用体的成员不能同时有效。当作"省空间的结构体"用,程序必然出错。
- "
union里可以随便存几个值"——只能存一个。写了u.c就破坏了u.i(下一节详细讲)。 - "共用体很少见,可以跳过"——考试会考,实际也会遇到(协议、二进制文件、嵌入式)。至少要能看懂、能算大小。
- "struct 和 union 关键字可以互换"——不行。它们是两种不同的内存安排,语法像不代表语义像。
自测三问(点开对答案)
1. 结构体和共用体在内存安排上的根本区别?——结构体成员**并排**(各占一块,互不干扰);共用体成员**重叠**(共用同一块内存,谁写谁占)。 2. `union { int i; char c; };` 的大小是多少?为什么?——4 字节。因为成员共用一块内存,大小取**最大的那个成员**(`int` 的 4 字节)。 3. 什么情况下该用共用体而不是结构体?——几个数据**互斥、同一时刻只可能用到其中一个**的时候(协议字段、类型可变的记录、省内存场合)。- ☐ 8.5.1 共用体的定义与声明(下一节)
相关笔记
- 使用指针访问结构体数组 —— 上一节:指针遍历结构体数组
- 共用体的定义与声明 —— 下一节:语法怎么写
- 结构体 —— 对照组:并排打包
- 结构体的大小 —— 对齐规则在共用体里同样生效
- 🔷 C++基础 · 索引 —— 全课路线图