联合体和结构体是C语言中两种重要的复合数据类型,它们可以相互嵌套使用,为复杂数据的表示提供了灵活的方式。
1. 联合体(Union)基础
联合体是一种特殊的数据类型,允许在相同的内存位置存储不同的数据类型。联合体的所有成员共享同一块内存空间。
union Data {int i;float f;char str[20];
};
特点:
-
所有成员共享同一内存空间
-
大小由最大成员决定
-
同一时间只能存储一个成员的值
2. 结构体(Struct)基础
结构体是将不同类型的数据组合成一个整体的数据类型。
struct Student {char name[50];int age;float score;
};
特点:
-
每个成员有自己的内存空间
-
大小是所有成员大小之和(考虑内存对齐)
-
可以同时存储所有成员的值
3. 联合体和结构体的嵌套使用
3.1 结构体中嵌套联合体
struct Variant {int type; // 用于标识当前存储的数据类型union {int i;float f;char c;} value;
};
// 使用示例
struct Variant var;
var.type = 0; // 假设0表示int
var.value.i = 10;
3.2 联合体中嵌套结构体
union Data {struct {int x;int y;} point;struct {float radius;float area;} circle;
};
// 使用示例
union Data data;
data.point.x = 10;
data.point.y = 20;
// 此时不能再使用circle成员,因为内存已被point占用
3.3 更复杂的嵌套
struct Employee {char name[50];int id;union {struct {float hourly_wage;int hours_worked;} hourly;struct {float annual_salary;float bonus;} salaried;} payment;int is_hourly; // 标志位,0表示salaried,1表示hourly
};
// 使用示例
struct Employee emp1;
emp1.is_hourly = 1;
strcpy(emp1.name, "John Doe");
emp1.id = 1001;
emp1.payment.hourly.hourly_wage = 15.50;
emp1.payment.hourly.hours_worked = 40;
4. 匿名联合体和结构体
C11标准引入了匿名联合体和结构体,可以简化访问:
struct Variant {int type;union {int i;float f;char c;}; // 匿名联合体
};
// 使用示例
struct Variant var;
var.type = 0;
var.i = 10; // 直接访问,不需要.value
5. 实际应用场景
-
变体类型:当需要表示多种类型但每次只使用一种时
-
节省内存:当多个数据不会同时使用时
-
硬件寄存器映射:表示同一寄存器不同位域的含义
-
协议解析:处理不同格式的网络数据包
-
类型转换:利用联合体实现不同类型数据的位模式转换
6. 注意事项
-
需要额外的标志字段来标识当前使用的成员
-
访问非当前活跃成员会导致未定义行为
-
初始化时只能初始化第一个成员
-
赋值会覆盖之前存储的值
-
在嵌入式系统中常用于节省内存空间