1. 联合体基础概念
联合体(union)是一种特殊的数据类型,允许在相同内存位置存储不同的数据类型 ,但同一时间只能使用一个成员。
cpp
union Data {
int i;
float f;
char str[20];
};
核心特性
-
所有成员共享同一块内存
-
大小由最大成员决定
-
同一时间只有一个成员有效
-
常用于节省内存 或类型转换场景
2. C语言中的联合体
2.1 基本用法
cpp
union Number {
int integer;
float real;
};
union Number num;
num.integer = 10; // 此时存储的是整数
printf("%d", num.integer);
num.real = 3.14; // 现在存储的是浮点数,整数值被覆盖
printf("%f", num.real);
2.2 内存布局示例
cpp
union {
int a; // 占用4字节
char b; // 占用1字节(与a共享前1字节)
} u;
3. C++中的联合体增强
3.1 成员函数(C++11起)
cpp
union SmartUnion {
int x;
double y;
void printX() { cout << x; } // C++允许成员函数
};
3.2 带构造函数/析构函数的类成员(C++11)
cpp
union ComplexUnion {
std::string str; // 可以包含非POD类型(需要手动管理)
int num;
ComplexUnion() {} // 需要自定义构造/析构
~ComplexUnion() {}
};
4. 经典应用场景
4.1 类型转换
cpp
union Converter {
float f;
unsigned int u;
} conv;
conv.f = 3.14;
printf("IEEE754表示: %X", conv.u); // 查看浮点数的二进制表示
4.2 协议解析
cpp
union Packet {
struct {
uint8_t header;
uint16_t payload;
} fields;
uint8_t raw[3]; // 以字节数组形式访问
};
4.3 内存优化
cpp
union Variant {
int i;
char c;
// 共用4字节内存而不是4+1
};
5. 联合体vs结构体
特性 | 联合体(union) | 结构体(struct) |
---|---|---|
内存使用 | 共享内存 | 每个成员独立内存 |
存储能力 | 只能存一个成员值 | 可存储所有成员值 |
大小计算 | 由最大成员决定 | 所有成员大小之和+对齐 |
访问控制 | 所有成员总是public | 可设置访问权限 |
6. 高级技巧与注意事项
6.1 匿名联合体(C11/C++)
cpp
struct Device {
enum { INT, FLOAT } type;
union { // 匿名联合体
int i;
float f;
};
};
Device d;
d.type = Device::FLOAT;
d.f = 2.718; // 直接访问
6.2 类型双关(Type Punning)
cpp
union {
uint32_t bits;
float value;
} converter;
converter.bits = 0x40490FDB; // 直接操作二进制位
printf("%f", converter.value); // 输出3.141592
⚠️ 注意:C++中类型双关可能违反严格别名规则,推荐使用
memcpy
代替
6.3 联合体位域
cpp
union StatusRegister {
uint16_t raw;
struct {
uint16_t error : 1; // 第0位
uint16_t ready : 1; // 第1位
uint16_t : 14; // 保留位
} bits;
};
7. 实际工程中的坑
-
初始化问题:
cppunion U { int a; float b; }; union U u = { .a = 10 }; // C99指定初始化
-
C++非POD类型管理:
cppunion { std::string s; // 必须手动管理生命周期 int x; } u; new (&u.s) std::string("hello"); // 手动构造 u.s.~string(); // 手动析构
-
字节序问题:
cppunion EndianTest { uint32_t num; uint8_t bytes[4]; } test = {0xAABBCCDD}; // 输出取决于平台字节序
8. C++17增强:带标签联合体
cpp
#include <variant> // C++17引入
std::variant<int, float, std::string> v;
v = 3.14f; // 当前存储float
if (auto p = std::get_if<float>(&v)) {
cout << *p; // 安全访问
}
9. 总结
联合体是内存高效 但需要谨慎使用的工具:
-
✅ 适合:底层编程、协议解析、类型转换
-
❌ 避免:需要同时存储多个值的场景
-
⚠️ 注意:类型安全、生命周期管理问题