C++联合体详解!

个人主页:PingdiGuo_guo

收录专栏:C++干货专栏

大家伙新年快乐,今天我们来了解一下C++联合体。

文章目录

1.联合体

1.1联合体的概念

1.2联合体的思想

1.3联合体的作用

1.3.1内存优化

1.3.2二进制数据操作

1.3.3类型转换

1.3.4解决特定问题

1.4联合体的操作

1.4.1定义联合体

1.4.2初始化联合体

1.4.3赋值操作

1.4.4访问联合体成员

1.4.5注意事项

1.5联合体的分类

1.5.1 匿名联合体(Anonymous Union)

1.5.2 命名联合体(Named Union)

1.5.3 嵌套联合体(Nested Union)

1.6联合体和结构体的区别

1.6.1 相同之处  

1.6.2 区别

1.7联合体的练习

1.7.1 题目

1.7.2 解题步骤

1.7.3 代码示例

         1.8总结


1.联合体

1.1联合体的概念

联合体是一种特殊的用户自定义数据类型,在C++中,通过`union`关键字来定义。它由多个成员组成,但所有成员共享同一段内存空间。联合体的大小等于其内部最大的成员所占的内存大小。

1.2联合体的思想

联合体的设计思想在于高效地利用内存,特别是在需要在不同时间点以不同类型的值来解释同一块内存的情况下。联合体确保了同一内存区域可被看作是多种数据类型的任何一种,但在任何时刻只有一个成员的数据是有意义的。

1.3联合体的作用

1.3.1内存优化

当不同的数据类型在某一时间段内互斥使用同一内存空间时,联合体可以避免不必要的内存开销。


1.3.2二进制数据操作

在处理底层数据,如网络通信协议、文件格式解析等领域,联合体常用于根据不同上下文对同一内存区域的不同解读。


1.3.3类型转换

在一些场景下,联合体可以作为一种简便的类型转换手段,尤其是从一种数据类型到另一种数据类型直接“重映射”内存内容。


1.3.4解决特定问题

在某些特定的应用场景中,联合体可以帮助程序员实现特定的需求,比如在有限的硬件资源条件下,或者在设计特定算法时需要灵活改变数据视图。

需要注意的是,使用联合体时应当谨慎,因为没有机制保证同时访问不同类型的成员是安全的,因此通常要求开发者自行管理联合体内存的正确使用。此外,C++11标准引入了std::variant,它是联合体的一种更安全的替代品,它可以持有多种类型并跟踪当前存储的有效类型。

1.4联合体的操作

1.4.1定义联合体
 

// 定义一个联合体,包含整型、浮点型和字符型成员
union MyUnion {
int integerValue;
float floatValue;
char characterValue;
};

在这个例子中,MyUnion是一个联合体,它有三个成员:一个整数、一个浮点数和一个字符。这三个成员共享相同的内存空间。

1.4.2初始化联合体
 

// 初始化联合体
MyUnion myU;
// 或者直接初始化某个成员
MyUnion myUInit = { .integerValue = 100 }; // C++11开始支持指定初始化标签



这里,myU创建了一个未初始化的联合体实例。而myUInit则直接初始化了integerValue为100。

1.4.3赋值操作
 

// 赋值操作,只能对当前活动成员赋值
myUInit.integerValue = 42; // 正确,现在联合体中保存的是整数值42// 尝试对非活动成员赋值(此时活动成员为integerValue)
myUInit.floatValue = 3.14f; // 实际上可能会覆盖掉integerValue的值// 更改活动成员
myUInit.characterValue = 'A'; // 现在联合体中保存的是字符'A',之前保存的整数值已丢失



由于联合体在同一时间只有一个活跃成员,所以对非活跃成员的赋值会覆盖当前活跃成员的数据,而且编译器不会发出警告或错误。


1.4.4访问联合体成员
 

// 访问联合体成员
int intValue = myUInit.integerValue; // 取回最后一次赋值给integerValue的值
char charValue = myUInit.characterValue; // 取回最后一次赋值给characterValue的值



访问联合体成员时,应确保了解当前哪个成员是活跃的,否则获取的数据可能是无意义的。


1.4.5注意事项

- 在实际使用联合体时,需要清楚知道当前活跃成员是什么,以免发生未预期的数据覆盖。
- 联合体本身不提供机制追踪当前活跃成员,这需要程序员自己管理和记录。在C++17中引入了std::variant作为更安全的替代方案,它能保持类型安全并跟踪当前存储的有效类型。

1.5联合体的分类

1.5.1 匿名联合体(Anonymous Union)

匿名联合体没有名称,只能定义在一个结构体或类的内部,并且可以与该结构体或类的其他成员共享相同的命名空间。

示例代码:

struct MyStruct {int type;union {int intValue;float floatValue;};
};int main() {MyStruct myVar;myVar.type = 0;myVar.intValue = 10;printf("%d\n", myVar.intValue);myVar.type = 1;myVar.floatValue = 3.14;printf("%.2f\n", myVar.floatValue);return 0;
}

1.5.2 命名联合体(Named Union)

命名联合体有一个特定的名称,可以在全局作用域或局部作用域中定义,并可以作为其他结构体,类等的成员。

示例代码:

     
 

union MyUnion {int intValue;float floatValue;
};int main() {MyUnion myVar;myVar.intValue = 10;printf("%d\n", myVar.intValue);myVar.floatValue = 3.14;printf("%.2f\n", myVar.floatValue);return 0;
}

1.5.3 嵌套联合体(Nested Union)


嵌套联合体是指一个联合体的成员也可以是另一个联合体。

示例代码:
 

union Union1 {int intValue;float floatValue;
};union Union2 {int intValue;Union1 nestedUnion;
};int main() {Union2 myVar;myVar.nestedUnion.intValue = 10;printf("%d\n", myVar.nestedUnion.intValue);myVar.nestedUnion.floatValue = 3.14;printf("%.2f\n", myVar.nestedUnion.floatValue);return 0;
}

1.6联合体和结构体的区别

联合体(Union)与结构体(Struct)在C++中都是复合数据类型,它们都可以容纳多个不同类型的成员变量,但在内存布局和使用方式上有显著区别:

1.6.1 相同之处  


1. 定义:两者都通过关键字定义,并且都能包含不同类型的成员变量。
2. 命名:都可以通过`.`运算符或者指向它们的指针的`->`运算符来访问成员变量。


1.6.2 区别


1. 内存布局


- 结构体:结构体的每个成员变量在内存中都有自己的独立空间,按照声明顺序依次排列。
- 联合体:联合体的所有成员变量共享同一片内存区域,同一时刻只能存放一个成员变量的值,改变一个成员变量会影响到其他成员变量的值,因为它们都在同一个内存位置上。

2. 使用


- 结构体:允许同时存储所有成员变量的值,每个成员变量的值都是独立存在的。
- 联合体:在同一时间只能有一个成员有效,也就是说,虽然可以声明多个类型的成员,但只能激活其中的一个用于存储数据。

3. 大小


- 结构体的大小至少是其所有成员变量大小之和(可能还要加上对齐导致的额外空间)。
- 联合体的大小等于其所有成员中最大的成员的大小,因为它只分配足够的空间来容纳最大成员。

4. 应用场景


- 结构体常用于打包相关数据到一起,创建一个新的数据类型,适用于需要同时维护多个状态的情况。
- 联合体常用于节省内存空间,尤其是在需要根据上下文临时存储不同类型数据而又不需要同时保存多种数据的情况下,例如在网络编程中转换不同类型的协议数据包。

总结来说,结构体是为数据聚合和分离提供便利,而联合体则是为了在有限的空间内存储不同类型的单个数据。

1.7联合体的练习

1.7.1 题目


编写一个程序,定义一个联合体类型,它可以存储一个整数值或一个浮点数值。然后编写函数分别读取用户输入的整数和浮点数,并通过联合体打印出两种不同的表示方式。最后,设计程序逻辑以确保在同一时间只有一个类型的值被正确存储和显示。

1.7.2 解题步骤

1. 定义一个联合体类型,包含整数(int)和浮点数(float)两个成员变量。
2. 编写一个函数,接收用户输入的整数,将其存入联合体,并打印整数值。
3. 编写另一个函数,接收用户输入的浮点数,将其存入联合体,并打印浮点数值。
4. 在主函数中,先读取整数并打印,然后读取浮点数并打印,注意每次存入新值时旧值会被覆盖。



1.7.3 代码示例

#include <iostream>// 定义联合体
union Number {
int intValue;
float floatValue;
};// 函数:读取整数并打印
void readAndPrintInt(Number &num) {
std::cout << "Enter an integer value: ";
std::cin >> num.intValue;
std::cout << "The integer value is: " << num.intValue << std::endl;
}// 函数:读取浮点数并打印
void readAndPrintFloat(Number &num) {
std::cout << "Enter a floating-point value: ";
std::cin >> num.floatValue;
std::cout << "The floating-point value is: " << num.floatValue << std::endl;
}int main() {
Number myNumber;// 先读取并打印整数
readAndPrintInt(myNumber);// 现在读取并打印浮点数
// 注意:由于联合体内存区域共用,此处会覆盖之前存储的整数值
readAndPrintFloat(myNumber);return 0;
}



大家请注意,尽管上述代码展示了如何使用联合体,但在实际应用中,直接读取不同类型的值并期望联合体能正确处理可能会有未定义行为的风险,特别是在没有显式地清除旧值的情况下。这是因为联合体不会自动跟踪当前生效的成员类型,因此从非活跃成员读取可能导致未定义的行为。在实际编程中,通常会配合额外的信息(如枚举或其他标记)来确定联合体当前存储的是哪种类型的值。

1.8总结

本篇博客到这里就结束了,感谢大家的支持与观看,如果有好的建议欢迎留言,谢谢大家啦!

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

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

相关文章

交叉熵损失函数基本概念及公式

Cross-Entropy Loss 1.二分类2. 对于多类别分类问题&#xff0c;其公式可以表示为&#xff1a;3. 公式深度挖掘解释——交叉熵损失函数公式中&#xff08;log&#xff09;的解释总结 交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09;是在机器学习和深度学习中常用的一…

Ainx-V0.2-简单的连接封装与业务绑定

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于Ainx系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列…

【EAI 020】Diffusion Policy: Visuomotor Policy Learning via Action Diffusion

论文标题&#xff1a;Diffusion Policy: Visuomotor Policy Learning via Action Diffusion 论文作者&#xff1a;Cheng Chi, Siyuan Feng, Yilun Du, Zhenjia Xu, Eric Cousineau, Benjamin Burchfiel, Shuran Song 作者单位&#xff1a;Columbia University, Toyota Research…

MATLAB知识点: unique函数 提取数组中的唯一值

​讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章 3.4.5 集合运算 unique函数可用来提取数组中的唯…

Stable Diffusion 模型下载:majicMIX lux 麦橘辉耀 - V3

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十

算法沉淀——位运算(leetcode真题剖析)

算法沉淀——位运算 常用位运算总结1.基础位运算2.确定一个数中第x位是0还是13.将一个数的第x位改成14.将一个数的第x位改成05.位图6.提取一个数最右边的17.删掉一个数最右边的18.异或运算9.基础例题 力扣题目讲解01.面试题 01.01. 判定字符是否唯一02.丢失的数字03.两整数之和…

LeetCode Python - 11.盛最多水的容器

文章目录 题目答案运行结果 题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&a…

计网day1

RTT&#xff1a;往返传播时延&#xff08;越大&#xff0c;游戏延迟&#xff09; 一.算机网络概念 网络&#xff1a;网样的东西&#xff0c;网状系统 计算机网络&#xff1a;是一个将分散得、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功…

web 前端实现一个根据域名的判断 来显示不同的logo 和不同的标题

1.需求 有可能我做一个后台 web端 我想实现一套代码的逻辑 显示不同的公司主题logo以及内容&#xff0c;但是实际上 业务逻辑一样 2.实现 建一个store oem.ts 这个名为是 oem系统 oem.ts import { defineStore } from pinia;import { store } from /store;const oemDataLis…

并行计算导论 笔记 1

目录 并行编程平台隐式并行超标量执行/指令流水线超长指令字处理器 VLIW 内存性能系统的局限避免内存延迟的方法 并行计算平台控制结构通信模型共享地址空间平台消息传递平台对比 物理组织理想并行计算机并行计算机互联网络网络拓朴结构基于总线的网络交叉开关网络多级网络全连…

【MySQL基础】:深入探索DQL数据库查询语言的精髓(上)

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. DQL1.1 基本语法1.2 基础查询1.3 条件查询1.3 聚合函数 &#x1f324;️ 全篇…

中文GPTS使用秘籍,字节扣子Coze工作流使用全教程

大家好&#xff0c;我是斜杠君。今天和大家分享字节扣子Coze工作流创建和使用全教程&#xff0c;手把手教会你。 首先我们先来看一下如何创建一个工作流。 我们以创建这样一个工作流为例。这个工作流程的作用是&#xff1a;把用户输入的内容通过头条接口查询信息&#xff0c;把…

MySQL篇----第二十一篇

系列文章目录 文章目录 系列文章目录前言一、什么是乐观锁二、什么是悲观锁三、什么是时间戳四、什么是行级锁前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、…

【Tauri】(1):使用Tauri1.5版本,进行桌面应用开发,在windows,linux进行桌面GUI应用程序开发,可以打包成功,使用 vite 最方便

1&#xff0c;视频地址&#xff1a; https://www.bilibili.com/video/BV1Pz421d7s4/ 【Tauri】&#xff08;1&#xff09;&#xff1a;使用Tauri1.5版本&#xff0c;进行桌面应用开发&#xff0c;在windows&#xff0c;linux进行桌面GUI应用程序开发&#xff0c;可以打包成功&…

第四节 zookeeper集群与分布式锁

目录 1. Zookeeper集群操作 1.1 客户端操作zk集群 1.2 模拟集群异常操作 1.3 curate客户端连接zookeeper集群 2. Zookeeper实战案例 2.1 创建项目引入依赖 2.2 获取zk客户端对象 2.3 常用API 2.4 客户端向服务端写入数据流程 2.5 服务器动态上下线、客户端动态监听 2…

mysql经典4张表问题

1.数据库表结构关联图 2.问题&#xff1a; 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数3.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩4、查询名字中含有"风"字的学生信息5、查询课程名称为"数学"&…

VMware虚拟机安装openEuler系统(二)(2024)

下面我们进行openEuler系统的一些简单配置。 1. 开启openEuler系统 在VMware Workstation Pro虚拟机软件中找到安装好的openEuler操作系统虚拟机并开启。 等待开启。 2. 安装配置 进入后选择第一个“Install openEuler 20.03-LTS”。 3. 选择系统语言 为虚拟机设置系统语言…

JVM垃圾回收机制及调优工具Arthas的使用

文章目录 1、JVM垃圾回收机制1.1 针对的内存区域1.2 怎么判断对象是否可以被回收&#xff1f;1.3 垃圾收集算法1.3.1 **标记-清除&#xff08;Mark-Sweep&#xff09;**1.3.2 复制&#xff08;Copying&#xff09;1.3.3 标记-整理&#xff08;Mark-Compact&#xff09;1.3.4 分…

python+flask+django医院预约挂号病历分时段管理系统snsj0

技术栈 后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django/flask Python版本&#xff1a;python3.7 数据库&#xff1a;mysql5.7 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm . 第一&#xff0c;研究分析python技术&#xff0c…

《Linux 简易速速上手小册》第3章: 文件系统与权限(2024 最新版)

文章目录 3.1 Linux 文件系统结构3.1.1 重点基础知识3.1.2 重点案例&#xff1a;设置一个 Web 服务器3.1.3 拓展案例 1&#xff1a;日志文件分析3.1.3 拓展案例 2&#xff1a;备份用户数据 3.2 理解文件权限3.2.1 重点基础知识3.2.2 重点案例&#xff1a;共享项目文件夹3.2.3 拓…