C 语言共用体:深入理解与实践】
目录
一、引言
二、共用体的定义和基本语法
三、共用体的使用
3.1 声明共用体变量
3.2 给共用体成员赋值
3.3 共用体的内存布局
四、共用体的应用场景
4.1 节省内存空间
4.2 处理不同类型的数据
五、共用体使用的注意事项
六、总结
一、引言
在 C 语言中,共用体(Union)是一种特殊的数据类型,它允许不同的数据类型共享同一块内存空间。与结构体(Struct)不同,结构体中的每个成员都有自己独立的内存位置,而共用体的所有成员共享同一段内存。这种特性使得共用体在某些特定场景下非常有用,比如节省内存空间或者处理不同类型的数据。
二、共用体的定义和基本语法
共用体的定义方式与结构体类似,使用 union 关键字。以下是一个简单的共用体定义示例:
cunion Data {int i;float f;char c;};
在这个例子中, union Data 定义了一个共用体类型,它包含三个成员:一个整数 i 、一个浮点数 f 和一个字符 c 。这些成员共享同一块内存空间,其大小为成员中占用内存最大的那个成员的大小。在大多数系统中, float 类型占用 4 个字节, int 类型通常也占用 4 个字节, char 类型占用 1 个字节,所以 union Data 占用 4 个字节的内存。
三、共用体的使用
3.1 声明共用体变量
可以使用以下方式声明共用体变量:
cunion Data myData;
3.2 给共用体成员赋值
由于共用体成员共享内存,同一时刻只能有一个成员的值是有效的。例如:
cmyData.i = 10;printf("myData.i = %d\n", myData.i);myData.f = 3.14;printf("myData.f = %f\n", myData.f);myData.c = 'A';printf("myData.c = %c\n", myData.c);
在上述代码中,先给 myData.i 赋值,然后输出其值。接着给 myData.f 赋值,此时 myData.i 的值已经被覆盖,因为它们共享同一块内存。最后给 myData.c 赋值, myData.f 的值也被覆盖。
3.3 共用体的内存布局
为了更好地理解共用体的内存共享机制,我们可以通过打印内存地址来观察:
c#include <stdio.h>union Data {int i;float f;char c;};int main() {union Data myData;printf("Address of myData: %p\n", &myData);printf("Address of myData.i: %p\n", &myData.i);printf("Address of myData.f: %p\n", &myData.f);printf("Address of myData.c: %p\n", &myData.c);return 0;}
运行上述代码,可以看到 myData 、 myData.i 、 myData.f 和 myData.c 的地址是相同的,这表明它们确实共享同一块内存空间。
四、共用体的应用场景
4.1 节省内存空间
当程序中需要处理不同类型的数据,但这些数据不会同时使用时,可以使用共用体来节省内存。例如,在一个简单的学生信息管理系统中,学生可能是本科生或者研究生,本科生有学号,研究生有学号和导师信息。可以使用共用体来存储学生的身份相关信息:
c#include <stdio.h>#include <string.h>union StudentInfo {int studentId;struct {int studentId;char advisor[50];} graduate;};struct Student {char name[50];char type[10]; // "undergraduate" 或 "graduate"union StudentInfo info;};int main() {struct Student student1, student2;// 本科生信息strcpy(student1.name, "Alice");strcpy(student1.type, "undergraduate");student1.info.studentId = 1001;// 研究生信息strcpy(student2.name, "Bob");strcpy(student2.type, "graduate");student2.info.graduate.studentId = 2001;strcpy(student2.info.graduate.advisor, "Professor Smith");if (strcmp(student1.type, "undergraduate") == 0) {printf("Undergraduate: %s, ID: %d\n", student1.name, student1.info.studentId);}if (strcmp(student2.type, "graduate") == 0) {printf("Graduate: %s, ID: %d, Advisor: %s\n", student2.name, student2.info.graduate.studentId, student2.info.graduate.advisor);}return 0;}
4.2 处理不同类型的数据
在一些设备驱动程序或者网络协议处理中,可能需要根据不同的情况处理不同类型的数据。共用体可以方便地实现这种功能。例如,在一个简单的通信协议中,数据包可能包含不同类型的数据:
c#include <stdio.h>union PacketData {int intData;float floatData;char stringData[20];};struct Packet {int type; // 1: int, 2: float, 3: stringunion PacketData data;};int main() {struct Packet packet1, packet2, packet3;// 整数类型数据包packet1.type = 1;packet1.data.intData = 42;// 浮点数类型数据包packet2.type = 2;packet2.data.floatData = 1.618;// 字符串类型数据包packet3.type = 3;strcpy(packet3.data.stringData, "Hello, world!");switch (packet1.type) {case 1:printf("Packet 1 (int): %d\n", packet1.data.intData);break;case 2:printf("Packet 2 (float): %f\n", packet2.data.floatData);break;case 3:printf("Packet 3 (string): %s\n", packet3.data.stringData);break;}return 0;}
五、共用体使用的注意事项
内存覆盖问题:由于共用体成员共享内存,要特别注意在使用时不要意外地覆盖了有用的数据。在给一个成员赋值之前,确保之前的值已经不再需要。
数据类型转换:在访问共用体的不同成员时,要注意数据类型的转换。例如,从一个存储整数的共用体成员读取数据并将其作为浮点数使用时,可能会得到不正确的结果,除非进行适当的类型转换。
结构体和共用体的嵌套:在使用结构体和共用体嵌套时,要理清内存布局和成员访问的逻辑,避免出现错误。
六、总结
共用体是 C 语言中一个强大而灵活的特性,它通过共享内存空间为我们提供了节省内存和处理不同类型数据的有效方式。在实际编程中,合理使用共用体可以提高程序的效率和灵活性,但同时也需要注意其使用的特殊性,避免出现内存和数据类型相关的问题。希望通过本文的介绍和示例,读者能够更好地理解和应用 C 语言中的共用体。
相关文章:
C 语言共用体:深入理解与实践】
目录 一、引言 二、共用体的定义和基本语法 三、共用体的使用 3.1 声明共用体变量 3.2 给共用体成员赋值 3.3 共用体的内存布局 四、共用体的应用场景 4.1 节省内存空间 4.2 处理不同类型的数据 五、共用体使用的注意事项 六、总结 一、引言 在 C 语言中,共…...
Oracle性能调优(一):时间模型统计
Oracle性能调优(一):时间模型统计 时间模型统计视图时间模型统计指标时间模型统计视图 📖 DB Time的含义: DB Time表示前台会话在数据库调用中所花费的总时间,它是衡量数据库实例总负载的一个重要指标。DB Time是从实例启动时开始累计测量的,其计算方法是将所有前台会话…...
012 rocketmq事务消息
文章目录 事务消息概念介绍交互流程事务消息原理TransactionListener接⼝TransactionProducer.javaTransactionConsumer.java 事务消息 内置topic中的消息对消费者不可见 本地事务mq消息事务消息 消息队列 RocketMQ 版提供的分布式事务消息适⽤于所有对数据最终⼀致性有强需求…...
SpringBoot原理-02.自动配置-概述
一.自动配置 所谓自动配置,就是Spring容器启动后,一些配置类、bean对象就自动存入了IOC容器当中,而不需要我们手动声明,直接从IOC容器中引入即可。省去了繁琐的配置操作。 我们可以首先将spring项目启动起来,里面有一…...
知识图谱+智能问诊预诊系统vue+django+neo4j架构、带问诊历史
文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站,有好处! 🤍编号:D032 🤍智能问答:智能问答自诊、预诊功能,同时可以保存问答历史 &…...
DeepSeek 助力 Vue3 开发:打造丝滑的悬浮按钮(Floating Action Button)
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
Java数据结构_一篇文章了解常用排序_8.1
本文所有排序举例均默认为升序排列。 目录 1. 常见的排序算法 2. 常见排序算法的实现 2.1 插入排序 2.1.1 基本思想: 2.1.2 直接插入排序 2.1.3 希尔排序(缩小增量排序) 2.2 选择排序 2.2.1 基本思想: 2.2.2 直接选择排…...
(南京观海微电子)——倍压设计与应用
在电路设计过程中,当后级需要的电压比前级高出数倍而所需要的电流并不是很大时,就可以使用倍压整流电路。倍压整流:可以将较低的交流电压,用耐压较高的整流二极管和电容器,“整”出一个较高的直流电压。 01 倍压整流电…...
AtCoder Beginner Contest AT_abc395_d ABC395D Pigeon Swap 题解
前言 在谎言中迷茫,试图躲避瓶颈。 可惜细节太多,浪费五发罚时。 一个绿名用户,被出题人卡住。 八十六分钟多,才看见一抹绿。 本题解 LaTeX \LaTeX LATEX 格式可能不太美观,以内容为主。 题目大意 有一群鸽子和它…...
网络安全-使用DeepSeek来获取sqlmap的攻击payload
文章目录 概述DeepSeek使用创建示例数据库创建API测试sqlmap部分日志参考 概述 今天来使用DeepSeek做安全测试,看看在有思路的情况下实现的快不快。 DeepSeek使用 我有一个思路,想要测试sqlmap工具如何dump数据库的: 连接mysql数据库&#…...
【含文档+PPT+源码】基于SpringBoot+Vue医药知识学习与分享平台的设计与实现
项目介绍 本课程演示的是一款 基于SpringBootVue医药知识学习与分享平台的设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署…...
coze生成的工作流,发布后,利用cmd命令行执行。可以定时发日报,周报等。让他总结你飞书里面的表格。都可以
coze生成的工作流,发布后,利用cmd命令行执行。可以定时发日报,周报等。让他总结你飞书里面的表格。都可以。 很简单。 准备工作,先发布你的工作流,和发布应用。 然后,点击扣子API 。 申请一个࿰…...
iOS for...in 循环
0x00 循环遍历一 输出结果是什么? NSMutableArray *marr [1, 2, 3].mutableCopy; for (NSNumber *number in marr) {NSLog("%", number);marr [4, 5, 6].mutableCopy; } NSLog("%", marr);0x01 循环遍历二 输出结果是什么? NS…...
《操作系统 - 清华大学》 9 -1:进程调度:背景
进程调度:基础概念与调度策略详解 在进程调度这部分,我们会涉及以下内容:背景介绍、各种各样的调度算法(包括通用操作系统的调度算法以及针对实时系统的算法),还会额外介绍一种调度算法。 一、CPU调度的背…...
NumPy的介绍
第四章:NumPy 基础 一 NumPy是什么 NumPy 数字集装箱 超级计算器。 NumPy 就像一台超级计算器,但它的计算对象不是简单的数字,而是成百上千个数字组成的「数字表格」。 假设你要统计全班 50 个同学的身高、体重、成绩,手动计算…...
【Python】基础语法三
> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解Python的函数、列表和数组。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自ÿ…...
使用 Spring Boot 和 Keycloak 的 OAuth2 快速指南
1. 概述 本教程是关于使用 Spring Boot 和 Keycloak 通过 OAuth2 配置后端的。 我们将使用 Keycloak 作为 OpenID 提供程序。我们可以将其视为负责身份验证和用户数据(角色、配置文件、联系信息等)的用户服务。它是最完整的 OpenID Connect ࿰…...
第三十六:6.6. 【$refs、$parent】
概述: $refs用于 :父→子。 $parent用于:子→父。 // 向外部提供数据 defineExpose({house}) 原理如下: 属性说明$refs值为对象,包含所有被ref属性标识的DOM元素或组件实例。$parent值为对象,当前组件…...
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 📚欢迎订阅专栏…...
【开源免费】基于SpringBoot+Vue.JS网络海鲜市场系统(JAVA毕业设计)
本文项目编号 T 222 ,文末自助获取源码 \color{red}{T222,文末自助获取源码} T222,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
抽象工厂模式:思考与解读
原文地址:抽象工厂模式:思考与解读 更多内容请关注: 引言 你是否曾经在开发系统时,需要创建一系列相关的对象,而这些对象需要共同协作并保持一致性?假设你有多个不同的产品类型,但它们需要在系统中一起工…...
【综合项目】api系统——基于Node.js、express、mysql等技术
目录 0 前言 1 初始化 2 注册登录 2.1 注册 2.1.1 功能:密码加密(2.3.3) 2.1.1.1 操作 2.1.1.2 bcryptjs详解 2.1.2 插入新用户(2.3.4) 2.1.3 优化:表单数据验证(2.5) …...
Go中slice和map引用传递误区
背景 关于slice和map是指传递还是引用传递,很多文章都分析得模棱两可,其实在Go中只有值传递,但是很多情况下是因为分不清slice和map的底层实现,所以导致很多人在这一块产生疑惑,下面通过代码案例分析slice和map到底是…...
C++ ++++++++++
初始C 注释 变量 常量 关键字 标识符命名规则 数据类型 C规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存 整型 sizeof关键字 浮点型(实型) 有效位数保留七位,带小数点。 这个是保…...
【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第1章 GPIO基础知识
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
linux在vim中查找和替换
在Linux中使用Vim编辑器查找文本的方法非常直观和强大。Vim是一个高度可配置的文本编辑器,支持多种查找和替换的命令。下面是一些基本的查找命令: 1. 向前查找 要向前查找文本,可以使用以下命令: /text_to_find 例如,…...
AWS中使用CloudFront分发API Gateway
首先需要准备一个Lambda function(Lambda->Functions) 还要准备一个证书,要覆盖子域名(AWS Certificate Manager->Certificates)。 1、API Gateway->Create API->REST API->Build->API endpoint type( Edge-optimized )-…...
探秘《矩阵之美》:解锁矩阵的无限魅力
在这个数据驱动的时代,矩阵作为数学中的瑰宝,不仅在理论研究中占据核心地位,更在工程技术、计算机科学、物理学、经济学等众多领域发挥着不可替代的作用。今天,让我们通过中科院大学耿修瑞老师(中科院空天信息研究院研…...
进行性核上性麻痹患者的生活护理指南
进行性核上性麻痹是一种神经系统退行性疾病,合理的生活护理能有效改善症状,提高生活质量。 居家环境要安全。移除地面杂物,铺设防滑垫,安装扶手,降低跌倒风险。在浴室、厨房等湿滑区域要特别加强防护措施。建议在床边、…...
JVM--虚拟机
JVM,即虚拟机,可以简单理解为将字节码文件翻译成机器码的机器。 .class文件-->机器码文件 JVM整体组成部分 1.类加载器 负责从磁盘中加载字节码文件到JVM中 2.运行时数据区 按照不同的数据分区进行存储(方法区,堆,栈,本地方…...
