C语言中联合体(union)的使用场景和内存布局是什么?
联合体基本概念:
-
定义和声明
cunion Data { int i; float f; char str[20]; }; union Data data; data.i = 10; data.f = 3.14; strcpy(data.str, "Hello"); -
内存共享特性
cunion Example { int value; char bytes[4]; }; union Example ex; ex.value = 0x12345678; // bytes[0] = 0x78 (小端序) // bytes[1] = 0x56 // bytes[2] = 0x34 // bytes[3] = 0x12
典型使用场景:
-
数据类型转换
cunion FloatInt { float f; unsigned int i; }; float_to_bits(float value) { union FloatInt converter; converter.f = value; return converter.i; } -
节省内存空间
c// 不使用联合体:占用12字节 struct Message { int type; union { int int_data; float float_data; char char_data[4]; } data; }; // 使用联合体:只占用8字节 union CompactMessage { struct { int type; int data; } int_msg; struct { int type; float data; } float_msg; }; -
网络协议解析
cunion IPHeader { struct { unsigned int version : 4; unsigned int ihl : 4; unsigned int tos : 8; unsigned int total_length : 16; } fields; unsigned int raw; }; -
变体数据类型
cenum DataType { INT, FLOAT, STRING }; struct Variant { enum DataType type; union { int int_val; float float_val; char *str_val; } value; };
内存布局分析:
-
大小计算
cunion SizeExample { char c; // 1字节 int i; // 4字节 double d; // 8字节 }; sizeof(union SizeExample); // 8字节(最大成员的大小) -
对齐规则
cunion AlignedExample { char c; int i; double d; }; // 大小为8字节,对齐到8字节边界
高级应用:
-
位域操作
cunion BitManipulation { unsigned int value; struct { unsigned int bit0 : 1; unsigned int bit1 : 1; unsigned int bit2 : 1; unsigned int rest : 29; } bits; }; union BitManipulation bm; bm.value = 0; bm.bits.bit0 = 1; -
类型安全的联合体
cstruct SafeUnion { enum { INT, FLOAT, STRING } type; union { int int_val; float float_val; char *str_val; } data; }; void print_safe_union(struct SafeUnion *su) { switch (su->type) { case INT: printf("%d\n", su->data.int_val); break; case FLOAT: printf("%f\n", su->data.float_val); break; case STRING: printf("%s\n", su->data.str_val); break; } }
注意事项:
-
同时访问问题
cunion Data { int i; float f; }; union Data d; d.i = 10; d.f = 3.14; // 覆盖了之前的值 // 此时访问 d.i 是未定义行为 -
字节序依赖
cunion EndianTest { int value; char bytes[4]; }; union EndianTest test; test.value = 1; if (test.bytes[0] == 1) { printf("Little Endian\n"); } else { printf("Big Endian\n"); } -
初始化
cunion Data { int i; float f; }; union Data d1 = {10}; // 初始化第一个成员 union Data d2 = {.f = 3.14}; // 指定成员初始化