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

八、联合使用中的注意事项
-
数据一致性:由于联合的成员共享内存,对一个成员的赋值可能会覆盖其他成员的值。因此,在使用联合时,必须非常小心,确保在读取一个成员的值时,它是最近被赋值的,并且没有被其他的赋值操作所破坏。
-
类型安全:C 语言对联合的类型检查相对较弱,需要程序员自己确保对联合成员的操作是合法和有意义的。不正确的使用可能导致未定义的行为和难以调试的错误。
-
可移植性:联合的内存布局和字节对齐可能因编译器和硬件平台而异。因此,在编写依赖于联合具体内存布局的代码时,要注意其可移植性问题。
联合是 C 语言中一个强大但需要谨慎使用的数据类型。

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

相关文章:
C 语言中的联合(Union)的用途是什么?
🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会! 📙C 语言百万年薪修炼课程 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。 文章目…...
汽车电子助力转向系统研究
汽车电子助力转向系统研究 摘要 电子助力转向系统(Electric Power Steering,EPS)是一种利用电动机辅助驾驶员进行车辆转向的系统。相比于传统的液压助力转向系统,EPS具有更高的效率、精确性和可控性。本文将详细探讨EPS的工作原理…...
大数据学习之 scala基础(补充)
scala基础: hello world: 写scala可运行文件的注意事项1、如果一个scala文件要运行,class要改成object2、如果是class,就仅单纯代表一个类,如果是object代表的是单例对象3、scala语法中,一句话结束不需要加分号4、sca…...
正向传播和反向传播
正向传播(Forward Propagation) 正向传播是指将输入数据通过神经网络,计算出预测值的过程。具体步骤如下: 输入层:接受输入数据。隐藏层:每个隐藏层中的神经元接收上一层的输出,进行加权求和&…...
前端文件下载的方式
方式一:a标签直接下载 <a href"链接" >下载</a>一个文件链接(一般是服务器上的某个文件),这个链接一般地址栏输入是预览,不是附件下载 如果想改成附件下载,以下两种方式任选一个均…...
视图库对接系列(GA-T 1400)十六、视图库对接系列(本级)通知(订阅回调)
说明 之前我们实现了订阅接口,其中有一个receiveAddr参数, 这个就是对应的回调的地址。一般情况下对应的是同一个服务。 我们推荐使用http://xxx:xxx/VIID/SubscribeNotifications接口文档 SubscribeNotificationList对象对象如下: 文档中是xml,但实际上目前使用的都是jso…...
Python | Leetcode Python题解之第230题二叉搜索树中第K小的元素
题目: 题解: class AVL:"""平衡二叉搜索树(AVL树):允许重复值"""class Node:"""平衡二叉搜索树结点"""__slots__ ("val", "parent&quo…...
Python酷库之旅-第三方库Pandas(018)
目录 一、用法精讲 44、pandas.crosstab函数 44-1、语法 44-2、参数 44-3、功能 44-4、返回值 44-5、说明 44-6、用法 44-6-1、数据准备 44-6-2、代码示例 44-6-3、结果输出 45、pandas.cut函数 45-1、语法 45-2、参数 45-3、功能 45-4、返回值 45-5、说明 4…...
九科bit-Worker RPA 内容学习
入门阶段, 花时间学习和记忆细枝末节,可能会反而分散新手去理解核心逻辑的精力,并且不常用的知识也很容易被遗忘。 简介: 什么是RPA? RPA(Robotic Process Automation,机器人流程自动化&#x…...
vscode编译环境配置-golang
1. 支持跳转 如果单测函数上方不显示run test | debug test,需要安装Code Debugger(因为以前的go Test Explorer不再被维护了) 2. 单测 指定单个用例测试 go test -v run TestXXXdlv 调试 需要安装匹配的go版本和delve版本(如…...
【JavaEE】网络编程——UDP
🤡🤡🤡个人主页🤡🤡🤡 🤡🤡🤡JavaEE专栏🤡🤡🤡 文章目录 1.数据报套接字(UDP)1.1特点1.2编码1.2.1DatagramSocket1.2.2DatagramPacket…...
JAVA毕业设计147—基于Java+Springboot的手机维修管理系统(源代码+数据库)
基于JavaSpringboot的手机维修管理系统(源代码数据库)147 一、系统介绍 本项目分为用户、管理员、维修员三种角色 1、用户: 注册、登录、新闻公告、售后申请、申请列表、意见反馈、个人信息、密码修改 2、管理员: 用户管理、用户管理、栏目管理、网…...
力扣第228题“汇总区间”
在本篇文章中,我们将详细解读力扣第228题“汇总区间”。通过学习本篇文章,读者将掌握如何遍历和汇总区间,并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释,以便于理解。 问题描述 力扣第228题“汇总区间”描…...
部署大语言模型并对话
在阿里云的https://developer.aliyun.com/adc/scenario/b105013328814fe995c0f091d708d67d 选择函数计算 设置服务器配置 复制公网地址 这个地址不能直接 在返回应用,创建应用LLM 对话页面 Open WebUI 点击下面的创建应用 部署完成后访问域名 打开访问地址...
WebSocket、socket.io-client
WebSocket WebSocket 是一种网络通信协议,它提供了一个在单个长期持久的 TCP 连接上进行全双工(full-duplex)通信的通道。 WebSocket 允许客户端和服务器之间进行双向的数据交换,这意味着服务器可以主动向客户端推送数据&#x…...
Maven 仓库
在 Maven 世界中,任何一个依赖、插件或者项目构建的输出,都可以称为 构件 。 坐标和依赖是构件在 Maven 世界中的逻辑表示方式,构件的物理表示方式是文件,Maven 通过仓库来统一管理这些文件。 任何一个构件都有一组坐标唯一标识。…...
给后台写了一个优雅的自定义风格的数据日志上报页面
highlight: atelier-cave-dark 查看后台数据日志是非常常见的场景,经常看到后台的小伙伴从服务器日志复制一段json数据字符串,然后找一个JSON工具网页打开,在线JSON格式化校验。有的时候,一些业务需要展示mqtt或者socket的实时信息展示,如果不做任何修改直接展示一串字符…...
【React Native优质开源项目】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...
Android 自动更新时间的数字时钟 TextClock
TextClock 继承 TextView ,使用方法和 TextView 一样。 它专门用于显示数字时钟,可以自定义显示格式。 只要在布局文件里添加,它会自动更新时间,不需要添加刷新逻辑。 布局文件, <?xml version"1.0"…...
【Linux Git入门】Git的介绍
文章目录 前言git简介git是什么git的作用为什么要学习git安装git总结前言 在现代软件开发中,版本控制系统已经成为了不可或缺的工具。其中,Git是最受欢迎的版本控制系统之一。Git是由Linux的创造者Linus Torvalds在2005年创建的,用于管理Linux内核的开发。Git是一个分布式版…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
