联合 (union) 是一种特殊的数据类型,它在同一内存区域存储不同的值。在 union 中,所有成员都位于同一内存地址,所占内存的大小等于最大成员的大小。
使用:
示例:
union Data { int i; float f; char s[4]; }; union Data d; d.i = 0x41424344; // 现在内存中是 4 个字节,可以作为 int、float、字符串读取 printf("%c%c%c\n", d.s[0], d.s[1], d.s[2]); // 供应商特定的输出
陷阱和使用规则:
问题: 使用 union 的意义何在,当我们可以直接使用包含多个字段的结构体?
答案: 使用 union 可以节省内存,因为在任何时刻只存储一个值,而不是同时存储所有值。在结构体中,每个字段都会分配内存,而在 union 中只为最大字段分配内存,其余字段“共享”这块内存。联合还允许在同一内存片段中安全地或故意地在不同数据表示之间进行转换。
示例:
struct S { int i; float f; } s; // sizeof = sizeof(int) + sizeof(float) union U { int i; float f; } u; // sizeof = max(sizeof(int),sizeof(float))
故事
在设备驱动程序项目中,通过带有位访问的数据的 union 与“硬件”进行通信。在小幅重构后,开发人员开始写入错误的 union 字段,导致读取到过期数据并导致系统崩溃,因为在 union 中每个时刻只有一个字段是“真实”的。
故事
在通过 union 进行网络数据包交换以管理内存时,开发人员忘记考虑结构的对齐。结果发生了一字节的偏移,结构以错误的偏移解析,这使得协议与原版不兼容。
故事
在编写序列化库时,程序员将 union 按值传递给函数,这里的字段在读取之前没有初始化。因此,数据序列化不正确,输出流中产生了垃圾,无法恢复原始信息。