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

深入理解 C 语言中的联合体

目录

引言

一、 联合体的定义与基本用法

1.联合体的定义

2.基本用法

二、 联合体与结构体的区别

1.结构体

2.联合体

3.对比 

三、联合体的优势

1. 节省内存

2. 提高效率

3. 代码简洁性

四、联合体的存储细节

1.内存对齐

2.大小计算

五、联合体的高级用法

1.匿名联合体

2.联合体数组

3.联合体进行类型转换

六、注意事项

总结


引言

联合体(union)是 C 语言中的一种特殊数据结构,允许在同一内存位置存储不同类型的数据。它与结构体(struct)类似,但存在显著的差异。理解联合体的定义、基本用法、优势、存储细节及其高级用法,有助于在实际编程中有效地使用这一数据结构。

一、 联合体的定义与基本用法

1.联合体的定义

在 C 语言中,联合体通过 union 关键字定义。其基本语法格式如下:

union 联合体名 {数据类型1 成员名1;数据类型2 成员名2;...
};

2.基本用法

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
union Data {int i;float f;char str[20];
};
int main() {union Data data;data.i = 10;printf("data.i = %d\n", data.i);data.f = 220.5;printf("data.f = %.1f\n", data.f);snprintf(data.str, sizeof(data.str), "Hello, World!");printf("data.str = %s\n", data.str);return 0;
}

运行结果:

e3dafa3eeec1412e96917eeecc9736de.png

union Data 定义了一个联合体 Data,它可以存储 int、float 或 char 数组。
由于所有成员共享同一块内存,因此设置一个成员的值会覆盖其他成员的值。

二、 联合体与结构体的区别

1.结构体

  • 内存分配:结构体中的每个成员都分配独立的内存区域,结构体的大小是所有成员大小之和(可能还会有填充字节)。
  • 数据存取:结构体的每个成员都可以独立地存取和修改。

2.联合体

  • 内存分配:联合体中的所有成员共享同一块内存,联合体的大小等于最大成员的大小。
  • 数据存取:同一时间只能访问一个成员,修改一个成员会覆盖其他成员的数据。

3.对比 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>typedef struct {char c;int i;
} MyStruct;typedef union {char c;int i;
} MyUnion;int main() {MyStruct s;MyUnion u;// 结构体s.c = 'a';s.i = 20;printf("Struct:\n字符:%c, 数字:%d \n", s.c, s.i);printf("Size of MyStruct:%d\n", sizeof(MyStruct));// 联合体u.c = 'a';printf("Union: \n字符:%c,", u.c);u.i = 20;printf("数字:%d\n", u.i);printf("Size of MyUnion:%d", sizeof(MyUnion));return 0;
}

运行结果:

3d583f4e39e64dc68941911398b217ce.png

内存示意图:

b16ccd9edfdc456b90a38494f16eb2bc.png

三、联合体的优势

1. 节省内存

由于联合体的所有成员共享同一块内存,联合体通常比结构体节省内存。在需要存储多种不同类型但不会同时使用的数据时,联合体特别有用。

2. 提高效率

联合体允许在不同数据类型之间进行高效的转换。对于需要在不同数据格式之间切换的应用场景,联合体能够简化数据处理和转换过程。

3. 代码简洁性

使用联合体可以减少代码中对数据类型的重复处理,提高代码的简洁性和可维护性。

四、联合体的存储细节

1.内存对齐

不同数据类型在内存中的对齐要求不同。联合体的内存对齐取决于最大成员的对齐要求。编译器可能会对联合体进行内存对齐,以提高访问效率。

联合体的内存对齐规则则如下:

联合体的第一个成员的地址和联合体本身的地址相同。
联合体的总大小是最大成员大小的整数倍。因为联合体中所有成员共享同一块内存,这块内存的大小必须足够容纳最大成员的大小。
联合体中每个成员的对齐要求必须满足最大成员的对齐要求。

2.大小计算

•联合的⼤⼩⾄少是最⼤成员的⼤⼩。
•当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤ 对⻬数的整数倍。

对⻬数 = 编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值

- VS 中默认的值为 8

- Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

示例:

#include <stdio.h>
union Un1
{char c[5];//共占5个字节int i;//最大对齐数,占4字节
};
union Un2
{short c[7];//共占14个字节int i;//最大对齐数,占4字节
};
int main()
{//下⾯输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}

运行结果:

27d3f4094b1e4a3ea66932aa6b76b618.png

五、联合体的高级用法

1.匿名联合体

匿名联合体(Anonymous Union)是一种不需要命名的联合体。它的主要作用是简化代码,特别是在结构体中直接访问联合体成员时,可以省略联合体的名字。

假设我们有一个结构体,其中包含一个匿名联合体用于存储不同的数据格式。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>typedef struct {int type;        // 数据类型标识符union {int i;float f;char str[20];}; // 匿名联合体
} DataPacket;int main() {DataPacket packet;// 设置为整数类型packet.type = 1;packet.i = 1234; // 直接访问联合体的成员printf("Packet Type: %d, Integer Value: %d\n", packet.type, packet.i);// 设置为浮点类型packet.type = 2;packet.f = 56.78;printf("Packet Type: %d, Float Value: %.2f\n", packet.type, packet.f);// 设置为字符串类型packet.type = 3;snprintf(packet.str, sizeof(packet.str), "Hello!");printf("Packet Type: %d, String Value: %s\n", packet.type, packet.str);return 0;
}

在 DataPacket 结构体中,union 定义为匿名联合体,因此可以直接访问其成员(如 i、f 和 str),而无需使用联合体名。

2.联合体数组

联合体数组用于存储多个联合体实例。每个联合体实例可以存储不同类型的数据,并且每个联合体实例共享相同的内存布局。

假设我们需要处理多个数据包,每个数据包可以包含不同类型的数据。我们可以使用联合体数组来管理这些数据包。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>typedef union {int i;float f;char str[20];
} DataUnion;int main() {DataUnion dataArray[3];// 设置数组元素为整数dataArray[0].i = 42;// 设置数组元素为浮点数dataArray[1].f = 3.14;// 设置数组元素为字符串snprintf(dataArray[2].str, sizeof(dataArray[2].str), "Union Array");// 打印数组元素printf("dataArray[0] (int): %d\n", dataArray[0].i);printf("dataArray[1] (float): %.2f\n", dataArray[1].f);printf("dataArray[2] (str): %s\n", dataArray[2].str);return 0;
}

DataUnion:定义了一个联合体,可以存储整数、浮点数或字符串。
dataArray[3]:创建了一个联合体数组 dataArray,包含 3 个 DataUnion 实例,每个实例可以存储不同的数据类型。
访问数组元素时,每个元素的内容可以根据需要进行设置和读取。 

3.联合体进行类型转换

联合体可以用作不同数据类型之间的转换工具。特别是,当需要将相同内存中的数据以不同格式进行解释时,联合体可以提供一种有效的方法。

假设我们有一个float数值,需要以int类型访问其位模式。这可以通过联合体进行实现。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>typedef union {float f;uint32_t i;
} FloatIntUnion;int main() {FloatIntUnion data;data.f = 3.14159; // 设置浮点数// 打印浮点数及其对应的整数位模式printf("Float value: %.5f\n", data.f);printf("Integer value: 0x%08X\n", data.i);return 0;
}

FloatIntUnion:联合体定义,其中一个成员是 float 类型,另一个成员是 uint32_t 类型。uint32_t 用于表示浮点数的位模式。
通过 data.f 设置浮点数,然后可以通过 data.i 访问该浮点数的内存位模式。这种方法用于调试、解析数据格式或其他低级操作。

六、注意事项

使用联合体时,应注意以下几点:

成员访问:确保在访问联合体的成员时,访问的是最近一次赋值的成员。
内存重叠:联合体成员之间的内存重叠可能导致数据损坏,因此使用时要格外小心。

总结

通过以上内容,我们深入了解了C语言中的联合体。合理使用联合体可以提高代码的灵活性和效率,但同时也需要谨慎处理可能出现的内存重叠和数据类型转换问题。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • JavaWeb基础1:HTML/CSS/JS/HTTP
  • 蓝屏事件:网络安全的启示
  • 云原生的候选应用
  • 静态代理与动态代理区别?
  • 记一次Mysql8.0使用GROUP BY查询导致异常问题
  • 供应链安全:黑客攻击 Nimble 包
  • 【LeetCode】133.克隆图
  • C#中常用集合类型
  • 室内宠物空气净化器哪个好?排名靠前室内宠物空气净化器使用感受
  • 详解Xilinx FPGA高速串行收发器GTX/GTP(3)--GTX的时钟架构
  • 白骑士的PyCharm教学高级篇 3.2 多模块项目管理
  • 谷粒商城实战笔记-129-商城业务-商品上架-nested数据类型场景
  • 用Java构建简单ATM系统
  • 白骑士的PyCharm教学进阶篇 2.5 数据库连接与管理
  • 基于深度学习的大规模模型训练
  • .pyc 想到的一些问题
  • 30天自制操作系统-2
  • AWS实战 - 利用IAM对S3做访问控制
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • canvas 高仿 Apple Watch 表盘
  • codis proxy处理流程
  • javascript面向对象之创建对象
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • mysql innodb 索引使用指南
  • node学习系列之简单文件上传
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • Theano - 导数
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 七牛云假注销小指南
  • 设计模式走一遍---观察者模式
  • 实现菜单下拉伸展折叠效果demo
  • 使用parted解决大于2T的磁盘分区
  • 事件委托的小应用
  • No resource identifier found for attribute,RxJava之zip操作符
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 阿里云ACE认证学习知识点梳理
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • #、%和$符号在OGNL表达式中经常出现
  • $.ajax()
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (四)JPA - JQPL 实现增删改查
  • (一) springboot详细介绍
  • (一)springboot2.7.6集成activit5.23.0之集成引擎
  • (转)VC++中ondraw在什么时候调用的
  • (转)德国人的记事本
  • (转)为C# Windows服务添加安装程序
  • (转载)利用webkit抓取动态网页和链接
  • .htaccess 强制https 单独排除某个目录