当前位置: 首页 > news >正文

[学习] 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);

典型应用场景:

  1. 结构体适用于需要同时存储多个相关数据的场景(如学生信息)
  2. 联合体适用于需要节省内存空间,且同一时间只需使用一种类型的场景(如协议解析)

二、核心差异对比

  • 内存分配方式
    结构体采用"内存叠加"方式,每个成员都分配独立的内存空间,且按声明顺序连续排列。例如一个包含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. 结构体场景

结构体常用于需要组合多个不同类型数据的场景,主要应用包括:

  1. 数据库记录存储

    • 可以表示完整的数据库表记录
    • 例如:员工信息(工号、姓名、部门、工资等)
  2. 对象建模

    • 几何图形:坐标点、矩形区域
    • 学生信息:学号、姓名、成绩
    • 商品信息: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. 联合体场景

联合体主要用于需要共享内存空间的场景,典型应用包括:

  1. 网络协议解析

    • 解析IP头部、TCP头部等网络协议字段
    • 方便以不同方式访问同一数据
  2. 硬件寄存器访问

    • 访问特殊功能寄存器
    • 既可以整体操作也可以位操作
  3. 类型转换

    • 实现类似变体类型(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. 注意事项

  1. 使用联合体时需要格外小心类型安全问题
  2. 需要额外的标识字段来指示当前使用的联合体成员
  3. 针对不同平台需要考虑内存对齐问题
  4. 在跨系统通信时要考虑字节序问题

这种设计模式极大地提高了数据结构的灵活性,同时保持了内存使用的高效性。


研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)


http://www.xdnf.cn/news/980533.html

相关文章:

  • 网络层 IP协议(第一部分)
  • Web前端基础之HTML
  • 通过Docker和内网穿透技术在Linux上搭建远程Logseq笔记系统
  • 对比学习(Contrastive Learning)方法详解
  • Docker Swarm overlay 和 docker_gwbridge
  • 我们来学mysql -- keepalive主从高可用
  • 线 性 数 据 结 构 双 雄:栈 与 队 列 的 原 理、实 现 与 应 用
  • K8S多维度问题排查
  • argocd部署cli工具并添加k8s集群
  • Spring cloud-k8s容器化部署
  • 6.10【Q】网络安全期末复习
  • 动态多目标进化算法:VARE(Vector Autoregressive Evolution)求解DF1-DF14,提供完整MATLAB代码
  • 线程(下)【Linux操作系统】
  • 鸿蒙Next仓颉语言开发实战教程:订单列表
  • 削皮刨结构化网格划分
  • Ubuntu 24.04 systemd-journald日志系统 journalctl 查看日志
  • 与AI联手,ModbusTCP 转Ethercat控制系统升级解决刚需新思路
  • 区块链世界的“破冰“之旅:比特币与以太坊首次组网全解析
  • 【MySQL进阶】MySQL程序
  • Spring Cache+Redis缓存方案 vs 传统redis缓存直接使用RedisTemplate 方案对比
  • 中心化交易所(CEX)架构:高并发撮合引擎与合规安全体系
  • Stream流常用方法大全
  • DAS-U250高性能分布式光纤声波传感器
  • 谷粒商城-分布式微服务 -集群部署篇[一]
  • MYSQL 字段切分特定值
  • 从 8 秒到 1 秒:前端性能优化的 12 个关键操作
  • 鱼书第三章代码MNIST
  • LVDS系列16:Xilinx 7系输出延迟ODELAYE2
  • AI实用特性
  • 使用R进行数字信号处理:婴儿哭声分析深度解析