联合体与类型双关
类型双关(type punning)是通过联合体以不同类型访问同一块内存的技术。C99 明确允许通过联合体进行类型双关,这是实现底层数据操作、序列化、协议解析等场景的重要工具。
通过联合体实现类型双关
union Converter {
int i;
float f;
};
union Converter c;
c.f = 3.14f;
printf("0x%08X\n", c.i); /* 查看 float 的位模式 */
字节访问
union IntBytes {
int value;
unsigned char bytes[4];
};
union IntBytes ib;
ib.value = 0x12345678;
for (int i = 0; i < 4; i++)
printf("%02X ", ib.bytes[i]);
/* 小端:78 56 34 12 */
/* 大端:12 34 56 78 */
指针转换方式(不推荐)
float f = 3.14f;
int *ip = (int *)&f; /* 违反严格别名规则 */
printf("%d\n", *ip); /* 未定义行为 */
/* 联合体方式是标准允许的 */
实际应用:协议解析
union Packet {
struct {
unsigned char header;
unsigned char length;
unsigned short data;
} fields;
unsigned char bytes[4];
unsigned int raw;
};
union Packet p;
p.raw = 0x12345678;
printf("header = %02X\n", p.fields.header);
常见错误
读取未初始化的成员:
union Converter c;
c.i = 10;
printf("%f\n", c.f); /* 未定义行为:未先写入 f */
假设字节序:
union IntBytes ib;
ib.value = 1;
if (ib.bytes[0] == 1) /* 小端检查 */
/* ... */
最佳实践
- 优先使用联合体而非指针转换
- 写入一个成员后,再读取该成员
- 注意字节序问题
- 类型双关主要用于底层编程