联合体(Union)简介
联合体(union
)是 C 和 C++ 编程语言中的一种数据结构,和结构体(struct
)类似,但有一些重要的区别。
定义
- 联合体中的所有成员共享同一段内存,也就是说,联合体中的多个成员变量会占用相同的地址,但是在任何一个时间点只能存储一个成员的值。
1. 联合体的定义和语法
定义语法
union UnionName {DataType member1;DataType member2;...
};
示例
union Example {int i; // 整数,占用 4 字节float f; // 浮点数,占用 4 字节char c; // 字符,占用 1 字节
};
- 这里的联合体
Example
包含了 3 个成员:- 一个整数
i
,占用 4 字节。 - 一个浮点数
f
,占用 4 字节。 - 一个字符
c
,占用 1 字节。
- 一个整数
- 存储特点:
- 联合体的总大小取决于它的最大成员所需的内存大小(这里是
4 字节
,因为int
和float
都占 4 字节)。
- 联合体的总大小取决于它的最大成员所需的内存大小(这里是
2. 联合体的内存分配
内存共享特点
- 联合体中的所有成员都共享同一块内存,因此:
- 写入一个成员会覆盖其他成员的值。
- 在任意时刻,联合体中只能存储一个有效值。
示例
union Example {int i; // 整数,占用 4 字节float f; // 浮点数,占用 4 字节char c[4]; // 字符数组,占用 4 字节
};
union Example ex;
ex.i = 42; // 写入整数 42
printf("i: %d\n", ex.i); // 输出 i 的值:42
ex.f = 3.14; // 写入浮点数 3.14
printf("f: %.2f\n", ex.f); // 输出 f 的值:3.14
printf("i: %d\n", ex.i); // 输出 i 的值:此时 i 的值已被覆盖
输出
i: 42
f: 3.14
i: 1078523331 // i 的值被 f 的写入覆盖,解释为浮点数的二进制形式
3. 联合体的用途
3.1 内存节省
- 联合体非常适合需要节省内存的场景。
- 由于多个成员共享同一段内存,可以显著减少内存占用。
3.2 数据转换
- 联合体常用于类型转换,允许以不同的方式访问同一块数据。
示例:浮点数与二进制表示的转换
#include <stdio.h>
union FloatToBits {float f;unsigned int bits;
};
int main() {union FloatToBits data;data.f = 3.14; // 写入浮点数printf("Float: %.2f\n", data.f); // 输出浮点数printf("Bits: 0x%X\n", data.bits); // 输出二进制表示return 0;
}
输出
Float: 3.14
Bits: 0x4048F5C3
- 同一块内存可以通过
data.f
访问为浮点数,通过data.bits
访问为其二进制位。
4. 联合体的常见用途
4.1 数据协议处理
- 联合体常用于解析二进制数据流。例如,在通讯协议中,可以通过联合体将字节流解析为特定的数据结构。
示例:解析 16 位数据的高低字节
union Data16 {unsigned short full; // 16 位数据struct {unsigned char low; // 低字节unsigned char high; // 高字节} parts;
};
int main() {union Data16 data;data.full = 0x1234; // 写入 16 位数据printf("Full: 0x%X\n", data.full); // 输出完整值printf("High: 0x%X\n", data.parts.high); // 输出高字节printf("Low: 0x%X\n", data.parts.low); // 输出低字节return 0;
}
输出
Full: 0x1234
High: 0x12
Low: 0x34
应用场景
- 网络协议:
- 在网络通讯中,经常需要解析协议头部,例如 IP 包头、TCP 包头等,联合体可以方便地拆解字段。
- 嵌入式开发:
- 在嵌入式系统中,用联合体将字节序列解析为多字节变量(如
int
或float
)。
- 在嵌入式系统中,用联合体将字节序列解析为多字节变量(如
4.2 硬件寄存器操作
- 联合体可以用于操作硬件寄存器,通过联合体直接访问寄存器的特定位。
示例:32 位寄存器的分段访问
union Register {unsigned int value; // 寄存器的完整值struct {unsigned char byte0; // 第 0 字节unsigned char byte1; // 第 1 字节unsigned char byte2; // 第 2 字节unsigned char byte3; // 第 3 字节} bytes;
};
int main() {union Register reg;reg.value = 0x12345678; // 写入寄存器值printf("Byte 0: 0x%X\n", reg.bytes.byte0); // 输出低字节printf("Byte 1: 0x%X\n", reg.bytes.byte1); // 输出次低字节printf("Byte 2: 0x%X\n", reg.bytes.byte2); // 输出次高字节printf("Byte 3: 0x%X\n", reg.bytes.byte3); // 输出高字节return 0;
}
输出
Byte 0: 0x78
Byte 1: 0x56
Byte 2: 0x34
Byte 3: 0x12
5. 联合体与结构体的区别
特性 | 联合体(union) | 结构体(struct) |
---|---|---|
内存分配 | 所有成员共享同一段内存,大小由最大成员决定 | 每个成员都有独立的内存,大小是所有成员内存之和 |
成员访问 | 同一时刻只能存储一个成员,访问其他成员可能导致数据不一致 | 所有成员可以同时访问,互不干扰 |
用途 | 内存节省,数据转换,多种数据形式的联合表示 | 表示多种属性的组合体 |
使用限制 | 不适合需要同时使用多个成员的场景 | 可以同时访问多个成员 |
6. 注意事项
- 数据覆盖:
- 由于所有成员共享内存,当你写入一个成员时,会覆盖其他成员的值。
- 使用联合体时要非常小心,确保对成员的访问逻辑正确。
- 对齐与大小:
- 联合体的大小由其最大成员的大小决定,并可能受到编译器对齐(padding)的影响。
- 联合体与类型安全:
- 联合体没有类型检查机制,读写不同类型的成员时可能导致不安全行为。
7. 总结
- 联合体是 C/C++ 中的一种高级数据类型,适用于节省内存、数据解析和类型转换等场景。
- 其核心特点是成员共享同一段内存,这既带来了灵活性,也对程序员提出了更高的使用要求。
- 常见用途包括:
- 数据协议解析(如解析高低字节)。
- 硬件寄存器操作。
- 浮点数与二进制位的转换。
- 节省内存空间的场景。
如有侵权,联系删除