C++联合体是一种特殊的复合数据类型,它通过union关键字定义,核心特点是所有成员共享同一段内存空间,同一时间只能存储其中一个成员的有效值。这种设计可以让多个不同类型的变量复用同一块内存,在需要节省内存的场景下非常实用。

union关键字的基本定义语法
使用union定义联合体和定义结构体的语法非常相似,只需要把struct换成union即可,基本结构如下:
// 定义一个存储不同数值类型的联合体
union Number {
int int_val; // 整型成员
float float_val;// 浮点型成员
double double_val;// 双精度浮点型成员
};
定义完成后,我们可以像使用其他类型一样声明联合体变量:
#include <iostream>
using namespace std;
union Number {
int int_val;
float float_val;
double double_val;
};
int main() {
Number num; // 声明联合体变量
return 0;
}
联合体的内存共享特性
联合体的所有成员从同一内存地址开始存储,整个联合体的大小等于其最大成员的大小,而不是所有成员大小之和。我们可以通过代码验证这个特性:
#include <iostream>
using namespace std;
union Number {
int int_val;
float float_val;
double double_val;
};
int main() {
Number num;
// 输出各个成员的地址,会发现地址相同
cout << "int_val地址: " << &num.int_val << endl;
cout << "float_val地址: " << &num.float_val << endl;
cout << "double_val地址: " << &num.double_val << endl;
// 输出联合体大小,等于double的大小(通常8字节)
cout << "联合体大小: " << sizeof(num) << endl;
return 0;
}
由于共享内存,给其中一个成员赋值后,其他成员的值会被覆盖,无法保证有效性:
#include <iostream>
using namespace std;
union Number {
int int_val;
float float_val;
};
int main() {
Number num;
num.int_val = 10;
cout << "赋值int后,int_val: " << num.int_val << endl;
// 此时float_val的值是无意义的,不要使用
num.float_val = 3.14f;
cout << "赋值float后,float_val: " << num.float_val << endl;
// 此时int_val的值已经被覆盖,不再是10
cout << "赋值float后,int_val: " << num.int_val << endl;
return 0;
}
联合体和结构体的核心区别
很多开发者会混淆union和struct,两者的核心差异如下:
| 对比项 | 联合体(union) | 结构体(struct) |
|---|---|---|
| 内存分配 | 所有成员共享同一段内存 | 每个成员有独立的内存空间 |
| 大小计算 | 等于最大成员的大小 | 所有成员大小之和(考虑内存对齐) |
| 有效成员 | 同一时间只有一个成员有效 | 所有成员可以同时存储有效值 |
联合体的常见使用场景
联合体通常用在以下场景:
- 需要存储多种类型但同一时间只会用一种的数据,比如通信协议中不同格式的报文数据
- 需要节省内存的嵌入式场景,避免多个互斥变量占用过多内存
- 需要以不同方式解读同一段内存数据,比如把一个32位整数拆成4个字节
下面是一个拆分整数的示例:
#include <iostream>
using namespace std;
union IntSplit {
int num;
unsigned char bytes[4]; // 假设int为4字节
};
int main() {
IntSplit split;
split.num = 0x12345678;
// 输出每个字节的值,验证内存拆分效果
for (int i = 0; i < 4; i++) {
cout << "第" << i << "个字节: " << hex << (int)split.bytes[i] << endl;
}
return 0;
}
使用联合体的注意事项
在使用union时需要注意几个问题:
- 不要同时访问多个成员,因为除了最后赋值的成员,其他成员的值都是未定义的
- 如果联合体包含有非平凡构造函数的类类型成员,需要谨慎处理,避免构造析构逻辑出错
- 可以通过额外的标记变量记录当前联合体存储的是哪个成员,避免误用无效成员
注意:C++11之后支持带构造函数和析构函数的类类型作为联合体成员,但需要手动管理成员的生命周期,使用时要格外小心。