C++ 枚举(enum)与联合体(union)全解析——从内存到底层机制全面掌握
目录
一、前言
二、枚举(enum)——可读性与类型安全的常量集合
1️⃣ 枚举的定义
2️⃣ 示例:自动与手动赋值
3️⃣ 稍复杂例子:断点递增
4️⃣ 枚举的本质:具名的整数常量
5️⃣ C++11 的强类型枚举(enum class)
✅ 小结:枚举的核心特性
三、联合体(union)——共享内存的多态数据结构
1️⃣ 定义与原理
2️⃣ 示例:共享内存效果
3️⃣ 内存图示(关键理解)
4️⃣ 典型应用场景
5️⃣ 示例:类型重解释(float ↔ int)
✅ 小结:联合体的核心特性
四、枚举 vs 联合体 对比总结
五、结语
承接我上篇文章关于数据结构:结构体、类、枚举和联合体做的拓展,详细介绍了枚举(enum)以及联合体(union)的内容:
C++派生数据类型与类型转换全解析(结构体、类、枚举、联合体对比+完整示例)-CSDN博客
https://blog.csdn.net/m0_58954356/article/details/154573750?spm=1001.2014.3001.5502
一、前言
在 C++ 的派生数据类型中,enum(枚举)与 union(联合体)虽然都属于用户自定义类型,但它们的用途、底层机制和语义完全不同:
-
枚举(enum):是一组具名的整数常量,提升代码可读性。
-
联合体(union):让多个成员共享同一块内存,实现类型复用和节省空间。
本篇文章将用示例和内存图带你一口气吃透这两个概念。
二、枚举(enum)——可读性与类型安全的常量集合
1️⃣ 枚举的定义
枚举类型用于定义一组命名的整数常量,语法如下:
enum 枚举名 {常量名1 [= 整型常量],常量名2 [= 整型常量],...
};
📌 要点:
-
枚举成员本质上是
int类型常量。 -
如果不赋值,系统默认从 0 开始递增。
-
如果中间赋值,后面从上一个值继续递增。
2️⃣ 示例:自动与手动赋值
#include <iostream>
using namespace std;enum Color { RED, GREEN = 5, BLUE };int main() {cout << "RED = " << RED << ", GREEN = " << GREEN << ", BLUE = " << BLUE << endl;return 0;
}
输出:
RED = 0, GREEN = 5, BLUE = 6
🔍 解释:
| 名称 | 是否赋值 | 实际值 | 说明 |
|---|---|---|---|
| RED | 否 | 0 | 第一个默认 0 |
| GREEN | 是 | 5 | 显式赋值 |
| BLUE | 否 | 6 | 从上一个(5)继续 +1 |
3️⃣ 稍复杂例子:断点递增
enum Week {MON, // 0TUE, // 1WED = 10, // 10THU, // 11FRI, // 12SAT = 20, // 20SUN // 21
};int main() {cout << MON << " " << TUE << " " << WED << " " << THU<< " " << FRI << " " << SAT << " " << SUN << endl;
}
输出:
0 1 10 11 12 20 21
4️⃣ 枚举的本质:具名的整数常量
其实,编译器会把它当成下面这样的宏常量:
const int RED = 0;
const int GREEN = 5;
const int BLUE = 6;
这样你在写代码时就不必记“魔法数字”,直接写 if (state == RED) 更易懂。
5️⃣ C++11 的强类型枚举(enum class)
C++11 引入了 enum class,解决传统枚举类型安全性差的问题。
enum class Color { RED, GREEN = 5, BLUE };int main() {Color c = Color::BLUE;cout << static_cast<int>(c) << endl; // 输出 6
}
📘 区别对比:
| 特性 | 传统 enum | 强类型 enum class |
|---|---|---|
| 定义方式 | enum Color {RED, GREEN}; | enum class Color {RED, GREEN}; |
| 作用域 | 全局,可直接用 RED | 需 Color::RED |
| 可隐式转 int | ✅ 是 | ❌ 否 |
| 类型安全 | ❌ 弱 | ✅ 强 |
| 用途 | 简单常量集合 | 更安全的枚举类型 |
✅ 小结:枚举的核心特性
| 特性 | 描述 |
|---|---|
| 默认从 0 开始递增 | 手动赋值会打断计数 |
| 底层是整型常量 | 可以直接输出或比较 |
| enum class 更安全 | 避免命名冲突与隐式转换 |
| 常用于状态机/模式枚举 | 如机器人状态、传感器状态等 |
三、联合体(union)——共享内存的多态数据结构
1️⃣ 定义与原理
联合体(union)与结构体类似,但所有成员共用同一段内存。
union 名称 {类型1 成员1;类型2 成员2;...
};
🧠 关键特性:
-
所有成员从同一个地址开始。
-
大小 = 最大成员的大小。
-
同一时间只能有效存储一个成员的值。
2️⃣ 示例:共享内存效果
#include <iostream>
using namespace std;union Data {int i;float f;char c;
};int main() {Data data;data.i = 10;cout << "i = " << data.i << endl;data.f = 3.14;cout << "f = " << data.f << endl;cout << "i (after f assigned) = " << data.i << endl; // 同块内存被覆盖
}
输出:
i = 10
f = 3.14
i (after f assigned) = 1078523331
3️⃣ 内存图示(关键理解)
假设联合体的大小为 4 字节:
┌────┬────┬────┬────┐ │ byte0 │ byte1 │ byte2 │ byte3 │ └────┴────┴────┴────┘ ↑ i, f, c 都从这个位置开始
-
data.i = 10→ 内存:0A 00 00 00 -
data.f = 3.14→ 内存被覆盖成:DB 0F 49 40 -
再读
data.i→ 把浮点的二进制当作整数读 →1078523331
4️⃣ 典型应用场景
| 场景 | 示例 | 说明 |
|---|---|---|
| 节省内存 | 嵌入式、通信协议 | 一段数据多种解释方式 |
| 协议帧解析 | 同一数据字段可为 int 或 float | |
| 类型重解释 | 读取相同字节内容的不同类型 | |
| 字节序分析 | 查看系统大端/小端存储 |
5️⃣ 示例:类型重解释(float ↔ int)
#include <iostream>
using namespace std;union Converter {int i;float f;
};int main() {Converter conv;conv.f = 3.14;cout << "float: " << conv.f << endl;cout << "as int: " << conv.i << endl;
}
输出:
float: 3.14
as int: 1078523331
📘 说明:
-
3.14的二进制表示(IEEE754)为0x40490FDB。 -
当用
int读取同一内存时,就会看到一个大整数。
✅ 小结:联合体的核心特性
| 特性 | 说明 |
|---|---|
| 所有成员共享同一块内存 | 同地址不同解释 |
| 大小 = 最大成员的大小 | 节省空间 |
| 不能同时保存多个值 | 写入一个会覆盖另一个 |
| 常用于底层解析 | 通信、嵌入式、驱动层 |
四、枚举 vs 联合体 对比总结
| 对比项 | 枚举(enum) | 联合体(union) |
|---|---|---|
| 本质 | 一组具名整型常量 | 共享内存的多成员结构 |
| 占用内存 | 各常量无存储 | 按最大成员大小分配 |
| 使用目的 | 提高可读性 | 节省空间或重解释数据 |
| 值类型 | 整型常量 | 可为任意类型 |
| 是否共用内存 | ❌ 否 | ✅ 是 |
| C++11 增强 | enum class | 无新语法,但可嵌套类内 |
| 典型场景 | 状态机、模式标识 | 通信协议、嵌入式设备 |
| 底层行为 | 常量递增规则 | 字节级内存共享 |
五、结语
✨ 一句话总结:
enum:让整数常量有名字,提升代码可读性与可维护性。
union:让多个成员共用同一内存,是底层程序设计的节省空间利器。
