[学习] C语言结构体与联合体的对比分析
C语言结构体与联合体的对比分析
文章目录
- C语言结构体与联合体的对比分析
- 一、定义
- 1. 结构体(struct)
- 2. 联合体(union)
- 二、核心差异对比
- 三、典型使用场景
- 1. 结构体场景
- 2. 联合体场景
- 四、混合使用案例
- 1. 网络协议头解析
- 2. 文件格式解析
- 3. 图形系统设计
- 4. 注意事项
一、定义
1. 结构体(struct)
结构体是一种用户自定义的数据类型,它允许将不同类型的数据项组合在一起作为一个整体来处理。结构体的每个成员都有独立的内存空间,成员之间互不干扰。
- 内存分配方式:结构体的大小等于所有成员大小的总和(考虑内存对齐)。例如在32位系统中,
int
通常占4字节,float
占4字节,char[20]
占20字节 - 声明语法:
struct 结构体标签 {数据类型 成员1;数据类型 成员2;... };
- 成员访问:使用点运算符(.)访问成员,如
stu.age
示例代码框架:
struct student {char name[20]; // 姓名,占用20字节int age; // 年龄,通常占用4字节float score; // 分数,通常占用4字节
}; // 整个结构体在32位系统中通常占用28字节(考虑对齐)// 使用示例
struct student stu1;
strcpy(stu1.name, "张三");
stu1.age = 18;
stu1.score = 89.5;
2. 联合体(union)
联合体是一种特殊的数据类型,它允许在同一内存位置存储不同的数据类型。但任何时候只能使用其中一个成员,所有成员共享同一块内存空间。
- 内存特性:联合体的大小等于其最大成员的大小
- 声明语法:
union 联合体标签 {数据类型 成员1;数据类型 成员2;... };
- 内存占用:联合体只分配足够容纳最大成员的内存空间
示例代码框架:
union data {int i; // 占用4字节float f; // 占用4字节char str[4];// 占用4字节
}; // 整个联合体占用4字节// 使用示例
union data value;
value.i = 10; // 存储整数
printf("%d", value.i);
value.f = 3.14; // 存储浮点数,之前存储的整数被覆盖
printf("%f", value.f);
典型应用场景:
- 结构体适用于需要同时存储多个相关数据的场景(如学生信息)
- 联合体适用于需要节省内存空间,且同一时间只需使用一种类型的场景(如协议解析)
二、核心差异对比
-
内存分配方式
结构体采用"内存叠加"方式,每个成员都分配独立的内存空间,且按声明顺序连续排列。例如一个包含int和char的结构体,在32位系统中将占用4+1=5字节(考虑对齐可能为8字节)。
联合体采用"内存重叠"方式,所有成员共享同一段内存空间,其大小为最大成员所需内存。例如同时包含int和char的联合体,只占用4字节(int所需空间),char将使用int的部分存储空间。 -
访问特性
结构体支持同时访问所有成员,各成员的值互不影响。例如可以同时读取student结构体的name和age字段。
联合体同一时间仅能有效访问一个成员,修改任一成员都会影响其他成员的值。如先给union的int成员赋值后,再读取char成员将得到int数据的部分字节。 -
应用目标
结构体适用于需要聚合多种数据的场景,如学生信息(学号、姓名、成绩等)、坐标点(x,y,z)等复合数据结构。
联合体主要用于:1)实现类型转换,如将float的二进制表示拆解为4个byte;2)节省内存空间,如在协议解析时,同一字段可能存储不同类型但不会同时使用。 -
典型示例
// 结构体示例 struct Student {char name[20];int age;float score; }; // 各字段独立存储// 联合体示例 union Data {int i;float f;char str[4]; }; // 所有字段共享内存
三、典型使用场景
1. 结构体场景
结构体常用于需要组合多个不同类型数据的场景,主要应用包括:
-
数据库记录存储
- 可以表示完整的数据库表记录
- 例如:员工信息(工号、姓名、部门、工资等)
-
对象建模
- 几何图形:坐标点、矩形区域
- 学生信息:学号、姓名、成绩
- 商品信息:ID、名称、价格、库存
实验示例详细说明:
#include <stdio.h>// 定义表示二维坐标点的结构体
struct point {int x; // x坐标int y; // y坐标
};int main() {// 初始化结构体实例struct point p = {3, 4};// 访问结构体成员并打印printf("坐标: (%d, %d)\n", p.x, p.y);// 修改结构体成员值p.x = 10;p.y = 20;printf("新坐标: (%d, %d)\n", p.x, p.y);return 0;
}
2. 联合体场景
联合体主要用于需要共享内存空间的场景,典型应用包括:
-
网络协议解析
- 解析IP头部、TCP头部等网络协议字段
- 方便以不同方式访问同一数据
-
硬件寄存器访问
- 访问特殊功能寄存器
- 既可以整体操作也可以位操作
-
类型转换
- 实现类似变体类型(Variant)的效果
- 实现数据类型的灵活转换
实验示例详细说明:
#include <stdio.h>// 定义联合体用于整数和字节数组的转换
union converter {int num; // 4字节整数char bytes[4]; // 4字节数组
};int main() {union converter c;// 赋值整数c.num = 0x12345678;// 通过字节数组访问printf("字节0: %02x\n", c.bytes[0]); // 低字节printf("字节1: %02x\n", c.bytes[1]);printf("字节2: %02x\n", c.bytes[2]);printf("字节3: %02x\n", c.bytes[3]); // 高字节// 修改字节影响整数值c.bytes[0] = 0xAA;printf("新整数值: %08x\n", c.num);return 0;
}
四、混合使用案例
结构体和联合体的组合使用在实际编程中非常常见,特别是在需要处理多种数据类型但又需要统一存储结构的场景。下面通过几个具体案例来展示这种组合的实用价值。
1. 网络协议头解析
在网络编程中,经常需要解析不同类型的协议数据包。使用结构体嵌套联合体可以高效地处理这种场景:
// 定义网络数据包结构
struct packet {int type; // 数据包类型标识union {int int_data; // 用于传输整数数据float float_data; // 用于传输浮点数据char str_data[64];// 用于传输字符串数据} payload; // 联合体存储不同类型的数据内容
};
使用方法示例:
struct packet pkt;
pkt.type = 1; // 设为整数类型
pkt.payload.int_data = 42; // 存储整数pkt.type = 2; // 设为浮点类型
pkt.payload.float_data = 3.14f; // 存储浮点数
2. 文件格式解析
在处理多种文件格式时,这种模式也非常有用:
struct file_header {char magic[4]; // 文件标识符int version; // 文件版本union {struct {int width;int height;} image_data; // 图像文件专用字段struct {int sample_rate;int channels;} audio_data; // 音频文件专用字段} format_data;
};
3. 图形系统设计
在图形系统中处理不同类型的图形对象:
struct graphic_object {int obj_type; // 1=圆形, 2=矩形, 3=三角形union {struct {float radius;} circle;struct {float width;float height;} rectangle;struct {float base;float height;} triangle;} attributes;
};
4. 注意事项
- 使用联合体时需要格外小心类型安全问题
- 需要额外的标识字段来指示当前使用的联合体成员
- 针对不同平台需要考虑内存对齐问题
- 在跨系统通信时要考虑字节序问题
这种设计模式极大地提高了数据结构的灵活性,同时保持了内存使用的高效性。
研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)