C 语言中的联合(Union)的用途是什么?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。

分割线

文章目录

  • C 语言中的联合(Union)的用途
  • 一、节省内存空间
  • 二、实现类型转换
  • 三、处理异构数据结构
  • 四、与硬件或特定编程环境交互
  • 五、示例:使用联合实现一个简单的变体类型
  • 六、联合的内存布局和字节对齐
  • 七、联合与结构体的区别
  • 八、联合使用中的注意事项

分割线


C 语言中的联合(Union)的用途

在 C 语言中,联合(Union)是一种特殊的数据类型,它允许在同一段内存空间中存储不同的数据类型。联合的主要用途包括节省内存空间、实现类型转换、处理异构数据结构以及与硬件或特定的编程环境进行交互等。

分割线

一、节省内存空间

在某些情况下,多个变量可能在不同的时间点被使用,但它们不会同时存在。此时,可以使用联合来共享同一块内存,从而节省内存空间。

例如,假设我们有一个程序需要处理两种不同类型的数据:整数和浮点数。如果分别定义两个变量来存储这两种类型的数据,那么将占用较多的内存空间。但如果这两个值不会同时被使用,我们就可以使用联合来节省内存:

union data {int intValue;float floatValue;
};int main() {union data myData;myData.intValue = 10;printf("Integer value: %d\n", myData.intValue);myData.floatValue = 3.14;printf("Float value: %f\n", myData.floatValue);return 0;
}

在上述示例中,myData 联合只占用了足够存储一个整数或一个浮点数的内存空间,而不是分别为整数和浮点数分配独立的内存空间。

分割线

二、实现类型转换

联合可以用于在不同的数据类型之间进行转换,而无需进行显式的类型强制转换操作。

以下是一个简单的示例,展示如何使用联合来实现类型转换:

union conversion {int intType;char charType;
};int main() {union conversion myConv;myConv.intType = 65;printf("Char value: %c\n", myConv.charType);myConv.charType = 'B';printf("Integer value: %d\n", myConv.intType);return 0;
}

在这个例子中,通过将一个整数赋值给 intType,然后读取 charType,实现了从整数到字符的隐式转换。反之亦然。

需要注意的是,这种类型转换方式可能导致未定义的行为,特别是当不同类型的大小和字节顺序不一致时。因此,在实际编程中应谨慎使用。

分割线

三、处理异构数据结构

当需要处理具有不同类型但相关的数据时,联合可以派上用场。

例如,考虑一个数据结构,其中可能包含不同类型的标识字段,如整数标识、字符串标识或枚举标识:

enum idType {INT_ID,STRING_ID,ENUM_ID
};union id {int intId;char stringId[20];enum idType enumId;
};struct dataRecord {union id identifier;// 其他数据成员
};int main() {struct dataRecord record;record.identifier.intId = 100;// 根据不同的情况设置和使用不同类型的标识return 0;
}

在上述示例中,根据具体的情况,可以选择使用联合中的不同成员来表示数据记录的标识符。

分割线

四、与硬件或特定编程环境交互

在某些与硬件接口或特定的编程环境中,联合常用于解析和处理具有特定格式的字节数据。

例如,当从硬件设备读取一个固定长度的字节序列,并需要根据不同的位或字节来解释其含义时,可以使用联合:

union hardwareData {unsigned char bytes[4];int integerValue;float floatValue;
};int main() {union hardwareData receivedData;// 假设从硬件读取了 4 个字节的数据到 receivedData.bytes// 根据具体的协议和格式来解释和使用数据return 0;
}

通过联合,可以根据硬件数据的格式和要求,灵活地以不同的方式解释和处理所接收的数据。

分割线

五、示例:使用联合实现一个简单的变体类型

下面是一个更综合的示例,展示如何使用联合来实现一个简单的变体类型,该类型可以存储整数、浮点数或字符串:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>enum dataType {INT_TYPE,FLOAT_TYPE,STRING_TYPE
};typedef struct variant {enum dataType type;union {int intValue;float floatValue;char *stringValue;} value;
} Variant;// 创建并初始化一个整数类型的变体
Variant *createIntVariant(int value) {Variant *v = (Variant *)malloc(sizeof(Variant));if (v == NULL) {return NULL;}v->type = INT_TYPE;v->value.intValue = value;return v;
}// 创建并初始化一个浮点数类型的变体
Variant *createFloatVariant(float value) {Variant *v = (Variant *)malloc(sizeof(Variant));if (v == NULL) {return NULL;}v->type = FLOAT_TYPE;v->value.floatValue = value;return v;
}// 创建并初始化一个字符串类型的变体
Variant *createStringVariant(const char *value) {Variant *v = (Variant *)malloc(sizeof(Variant));if (v == NULL) {return NULL;}v->type = STRING_TYPE;v->value.stringValue = (char *)malloc(strlen(value) + 1);if (v->value.stringValue == NULL) {free(v);return NULL;}strcpy(v->value.stringValue, value);return v;
}// 打印变体的值
void printVariant(Variant *v) {switch (v->type) {case INT_TYPE:printf("Integer: %d\n", v->value.intValue);break;case FLOAT_TYPE:printf("Float: %f\n", v->value.floatValue);break;case STRING_TYPE:printf("String: %s\n", v->value.stringValue);break;}
}// 释放变体占用的内存
void freeVariant(Variant *v) {if (v == NULL) {return;}switch (v->type) {case STRING_TYPE:free(v->value.stringValue);break;}free(v);
}int main() {Variant *intVar = createIntVariant(42);Variant *floatVar = createFloatVariant(3.14);Variant *stringVar = createStringVariant("Hello, World!");printVariant(intVar);printVariant(floatVar);printVariant(stringVar);freeVariant(intVar);freeVariant(floatVar);freeVariant(stringVar);return 0;
}

在这个示例中,我们定义了一个 Variant 结构体,其中包含一个类型枚举和一个联合。通过不同的创建函数,可以创建不同类型的变体,并使用 printVariant 函数打印其值,最后使用 freeVariant 函数释放内存。

分割线

六、联合的内存布局和字节对齐

联合的内存布局是由其成员中占用最大内存空间的成员决定的。所有成员共享同一块内存区域,并且起始地址相同。

字节对齐会对联合的内存布局产生影响。字节对齐是为了提高内存访问效率,通常按照特定的规则将数据存储在内存中的特定地址上。

例如,如果一个系统的字节对齐要求是 4 字节,而联合的成员分别是一个 1 字节的字符和一个 4 字节的整数,那么联合的内存大小将是 4 字节,并且字符也会从 4 字节的边界开始存储。

#include <stdio.h>union alignExample {char c;int i;
};int main() {printf("Size of union: %zu\n", sizeof(union alignExample));return 0;
}

在不同的编译环境和系统中,字节对齐的规则和大小可能会有所不同。

分割线

七、联合与结构体的区别

联合和结构体在 C 语言中都是复合数据类型,但它们有一些关键的区别:

  1. 内存布局:结构体的每个成员都有自己独立的内存空间,按照声明的顺序依次排列。而联合的所有成员共享同一块内存空间。
  2. 访问方式:在结构体中,可以同时访问和使用所有的成员。但在联合中,在任何给定的时间,只有最后被赋值的成员是有效的和有意义的访问。
  3. 用途:结构体通常用于将不同类型但相关的数据组合在一起,每个成员都有其独立的含义和用途。联合则更适合用于表示在不同时间使用不同类型的数据,或者在不同的情况下对同一块内存进行不同的解释。

分割线

八、联合使用中的注意事项

  1. 数据一致性:由于联合的成员共享内存,对一个成员的赋值可能会覆盖其他成员的值。因此,在使用联合时,必须非常小心,确保在读取一个成员的值时,它是最近被赋值的,并且没有被其他的赋值操作所破坏。

  2. 类型安全:C 语言对联合的类型检查相对较弱,需要程序员自己确保对联合成员的操作是合法和有意义的。不正确的使用可能导致未定义的行为和难以调试的错误。

  3. 可移植性:联合的内存布局和字节对齐可能因编译器和硬件平台而异。因此,在编写依赖于联合具体内存布局的代码时,要注意其可移植性问题。

联合是 C 语言中一个强大但需要谨慎使用的数据类型。


分割线

🎉相关推荐

  • 📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。
  • 🍅博客首页-关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
  • 📙CSDN专栏-C语言修炼
  • 📙技术社区-墨松科技

C语言



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3225206.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

JS代码动态打印404页面源码

JS代码动态打印404页面源码&#xff0c;适合做网站错误页&#xff0c;具有js动态打印效果&#xff0c;喜欢的朋友可以拿去 源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务…

LLM-大模型私有模型训练步骤方法总结

文章目录 前言预训练&#xff08;Pretrained&#xff09;步骤模型选择确定应用场景数据采集清理数据预训练模型 微调&#xff08;Fine Tuning&#xff09;合规对齐 (Alignment)集成 LLM 至 APP总结 前言 本文将从宏观层面说明 LLM 私有模型的训练步骤&#xff0c;包括预训练&a…

Flutter 开启混淆打包apk,并反编译apk确认源码是否被混淆

第一步&#xff1a;开启混淆并打包apk flutter build apk --obfuscate --split-debug-info./out/android/app.android-arm64.symbols 第二步&#xff1a;从dex2jar download | SourceForge.net 官网下载dex2jar 下载完终端进入该文件夹&#xff0c;然后运行以下命令就会在该…

java中方法的使用

方法的使用 方法的概念什么是方法方法定义方法的调用过程实参和形参的关系 方法重载为什么需要方法重载方法重载的概念方法签名 递归递归的概念递归过程分析递归练习 方法的概念 什么是方法 方法就是一个代码片段&#xff0c;类似于C语言的函数。 方法存在的意义&#xff1a;…

诸葛亮的连环计 责任链模式

“万事谋定而后动&#xff0c;一环扣一环&#xff0c;方能成大事。” 在三国时期&#xff0c;诸葛亮以其超凡的智慧闻名天下。在他众多的计策中&#xff0c;有一个鲜为人知却极具智慧的连环计&#xff0c;完美诠释了现代软件设计中的责任链模式。让我们一同探索这个巧妙的计策…

zookeeper加入开机启动项

Windows的任务计划程序&#xff08;Task Scheduler&#xff09;是一个强大的工具&#xff0c;允许你安排程序在特定时间自动运行&#xff0c;包括开机时。 打开任务计划程序&#xff1a; 按下Win R键&#xff0c;打开“运行”对话框。输入taskschd.msc并回车&#xff0c;打开…

数据结构--单向链表篇(python实现)

写在开头 链表&#xff08;Linked list&#xff09;是一种常见的基础数据结构&#xff0c;是一种线性表&#xff0c;但是并不会按线性的顺序存储数据&#xff0c;而是在每一个节点里存到下一个节点的指针(Pointer) 链表的优缺点 优点 不需要预先知道数据大小&#xff0c;实现灵…

前端面试题37(js递归)

在JavaScript中&#xff0c;递归是一种编程技术&#xff0c;它允许函数调用自身来解决问题。这种方法通常用于处理分治策略的算法&#xff0c;比如遍历树形结构、计算阶乘、 Fibonacci数列等。下面通过几个示例来说明如何使用递归。 1. 计算阶乘 阶乘是一个经典的递归示例&am…

硬盘分区读不出来的应对策略与数据恢复实战

在日常的计算机使用过程中&#xff0c;硬盘分区读不出来的问题时常困扰着用户。这一故障不仅可能导致重要数据的突然失联&#xff0c;还可能对系统的稳定运行造成威胁。硬盘分区读不出来&#xff0c;往往表现为在文件资源管理器中无法访问特定分区&#xff0c;系统提示错误或分…

信创:鲲鹏(arm64)+麒麟(kylin v10)离线部署k8s和kubesphere(含离线部署新方式)

本文将详细介绍&#xff0c;如何基于鲲鹏CPU(arm64)和操作系统 Kylin V10 SP2/SP3&#xff0c;利用 KubeKey 制作 KubeSphere 和 Kubernetes 离线安装包&#xff0c;并实战部署 KubeSphere 3.3.1 和 Kubernetes 1.22.12 集群。 服务器配置 主机名IPCPUOS用途master-1192.168.10…

jitsi 使用JWT验证用户身份

前言 Jitsi Meet是一个很棒的会议系统,但是默认他运行所有人创建会议,这样在某种程度上,我们会觉得他不安全,下面我们就来介绍下使用JWT来验证用户身份 方案 卸载旧的lua依赖性sudo apt-get purge lua5.1 liblua5.1-0 liblua5.1-dev luarocks添加ubuntu的依赖源,有则不需…

D2D用户的功率优化算法研究

D2D通信技术是指两个对等的用户节点之间直接进行通信的一种通信方式。在由D2D通信用户组成的分布式网络中&#xff0c;每个用户节点都能发送和接收信号&#xff0c;并具有自动路由(转发消息)的功能。网络的参与者共享它们所拥有的一部分硬件资源&#xff0c;包括信息处理、存储…

HTML5表单的自动验证、取消验证、自定义错误信息

1、自动验证 通过在元素中使用属性的方法&#xff0c;该属性可以实现在表单提交时执行自动验证的功能。下面是关于对元素内输入内容进行限制的属性的指定。 属性说明required输入内容是否不为空pattern输入的内容是否符合指定格式min、max输入的数值是否在min~max范围step判断…

使用Maven命令将第三方jar包安装到maven本地仓库

使用Maven命令将第三方jar包安装到maven本地仓库 事例&#xff1a; 第三方jar包 &#xff1a;common-pojo-1.0-SNAPSHOT.jar Maven命令 mvn install:install-file -Dfilejar包在本地磁盘的路径 -DgroupId组织名称 -DartifactId项目名称 -Dversion版本号 -Dpackaging打包方式 完…

【初阶数据结构】1.算法复杂度

文章目录 1.数据结构前言1.1 数据结构1.2 算法1.3 如何学好数据结构和算法 2.算法效率2.1 复杂度的概念2.2 复杂度的重要性 3.时间复杂度3.1 大O的渐进表示法3.2 时间复杂度计算示例3.2.1 示例13.2.2 示例23.2.3 示例33.2.4 示例43.2.5 示例53.2.6 示例63.2.7 示例7 4.空间复杂…

乐器培训课程报名小程序模板源码

模板介绍 一款实用的音乐课程&#xff0c;乐器培训&#xff0c;艺术类网页课程报名手机小程序模板下载。包含&#xff1a;主页、列表、个人中心、报名等模块。 图片演示 乐器培训课程报名小程序模板源码

6.MkDocs附录

安装插件 在 MkDocs 中&#xff0c;插件通常是通过 pip​ 工具安装的。你可以使用以下步骤来安装和配置 MkDocs 插件。 1.使用 pip​ 命令安装你需要的插件。例如 pip install pymdown-extensions‍ 2.更新 mkdocs.yml​ 文件。 ‍ 3.使用 mkdocs serve​ 命令本地预览你…

PHP禁止IP访问和IP段访问(代码实例)

PHP禁止IP和IP段访问 实现IP限制是Web开发中常见的需求之一&#xff0c;它可以用于限制特定IP地址的访问权限。在PHP中&#xff0c;我们可以通过一些方法来实现IP限制。 <?//禁止某个IP$banned_ip array ("127.0.0.1",//"119.6.20.66","192.168.…

旷野之间2 - 如何训练医疗保健小型语言模型(AI-SLM)

​​​​ 在本文中,我们将研究如何针对疾病症状训练一个小型医疗保健语言模型。为此,我们将从HuggingFace获取数据集(用于训练我们的模型):https://huggingface.co/datasets/QuyenAnhDE/Diseases_Symptoms QuyenAnhDE/Diseases_Symptoms 数据集来自 Hugging Face。图片来源…

cesium 雷达扫描

cesium 雷达扫描 (下面附有源码) 实现思路 1、通过改变圆型材质来实现效果, 2、用了模运算和步进函数(step)来创建一个重复的圆形图案 3、当纹理坐标st落在垂直或水平的中心线上时,该代码将改变透明度和颜色,以突出显示这些线 示例代码 <!DOCTYPE html> <ht…