C/C++ union联合体介绍
C/C++ union联合体介绍
文章参考:https://blog.csdn.net/mooneve/article/details/92703036
1. 联合体union简介
union
是在某种程序上类似结构体struct
的一种数据结构,union
也可以包含很多种数据类型和变量,区别在于:
- 结构体中所有变量是共存的,内存空间的分配是粗放的,不管用不用,都会分配;
- union中个变量是互斥的,任何两个成员不会同时有效,内存使用更精细灵活,节省内存空间。
当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体。
在《C Programming Language》中对联合体union的描述:
- 联合体是一个结构体;
- 它的所有成员相对于基地址的偏移量是0;
- 此结构空间要大到足够容纳最宽的成员;
- 其内存对齐方式要适合其中所有的成员;
联合体union定义形式如下:
union 名称{
public: // 默认为public,可不写
公有成员
protected:
保护成员
privated:
私有成员
};
示例,无名联合体声明和使用
union{
int i;
float f;
}
i=1;
f=1.2;
示例:使用联合体管理成绩信息
/**
* @file 1unioc.cpp
* @author zoya (2314902703@qq.com)
* @brief 联合体使用:使用联合体保存信息并数据
* @version 0.1
* @@date: 2022-10-08
*
* @copyright Copyright (c) 2022
*
*/
#include <iostream>
#include <string>
using namespace std;
class ExamGradeInfo
{
private:
string name; // 课程名
enum
{
LEVEL,
PASS,
GRADE,
} mode; // 计分方式
union
{
char level; // 等级表示成绩 A/B/C等
bool pass; // 只计算是否通过
int grade; // 具体的分数
};
public:
ExamGradeInfo();
ExamGradeInfo(string name, char level) : name(name),
mode(ExamGradeInfo::LEVEL),
level(level)
{
}
ExamGradeInfo(string name, bool pass) : name(name),
mode(ExamGradeInfo::PASS),
pass(pass)
{
}
ExamGradeInfo(string name, int grade) : name(name),
mode(ExamGradeInfo::GRADE),
grade(grade)
{
}
void show()
{
cout << name << ":";
switch (mode)
{
case ExamGradeInfo::LEVEL:
cout << level << endl;
break;
case ExamGradeInfo::PASS:
cout << (pass?"PASS":"FAILE") << endl;
break;
case ExamGradeInfo::GRADE:
cout << grade << endl;
break;
default:
break;
}
}
};
int main()
{
ExamGradeInfo course1("english", 'B');
ExamGradeInfo course2("math", true);
ExamGradeInfo course3("C", 60);
course1.show();
course2.show();
course3.show();
return 0;
}
运行显示结果:
english:B
math:PASS
C:60
2. 联合体union内存分配与所占空间
联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系,其大小必须满足两个条件:
- 大小足够容纳最宽的成员;
- 大小能被其包含的所有的基本数据类型的大小整除。
示例:测试如下联合体所占的大小:
/**
* @file 2union.c
* @author zoya (2314902703@qq.com)
* @brief 测试联合体所占内存大小
* @version 0.1
* @@date: 2022-10-08
*
* @copyright Copyright (c) 2022
*
*/
#include <stdio.h>
int main()
{
union u1
{
int n;
char s[5];
double f;
};
union u2
{
int n;
char s[9];
double f;
};
u1 tmp1;
u2 tmp2;
printf("sizeof(int) = %ld, sizeof(char) = %ld, sizoef(douvle) = %ld\n", sizeof(int), sizeof(char), sizeof(double));
printf("sizeof(u1) = %ld, sizeof(u2) = %ld\n", sizeof(tmp1), sizeof(tmp2));
printf("u1各个变量的地址, &u1 : 0x%x, &u1.n : 0x%x, &u1.s : 0x%x, &u1.f : 0x%x\n",
&tmp1, &tmp1.n, tmp1.s, &tmp1.f);
printf("u2各个变量的地址, &u2 : 0x%x, &u2.n : 0x%x, &u2.s : 0x%x, &u2.f : 0x%x\n",
&tmp2, &tmp2.n, tmp2.s, &tmp2.f);
return 0;
}
运行结果:
sizeof(int) = 4, sizeof(char) = 1, sizoef(douvle) = 8
sizeof(u1) = 8, sizeof(u2) = 16
u1各个变量的地址, &u1 : 0x5ec19748, &u1.n : 0x5ec19748, &u1.s : 0x5ec19748, &u1.f : 0x5ec19748
u2各个变量的地址, &u2 : 0x5ec19750, &u2.n : 0x5ec19750, &u2.s : 0x5ec19750, &u2.f : 0x5ec19750
对联合体u1,n占4字节,f占8字节,s占5字节,u1最多占用8个字节,所以sizoef(u1)=8;
对联合体u2,n占4字节,f占8字节,s占9字节,最多占用了9字节,但是9字节不能被double所占的8字节整除,所以就会扩充到16字节,所以sizeof(u2) = 16;
另外,还可以发现联合体中各个变量的地址都是相同的。
3. 联合体union的优缺点
联合体的优点:多种访问内存的手段可以灵活读取任意部分的数据,也可整体进行赋值。在某些寄存器或通道大小有限制的情况下,可以分多次搬运;
联合体的缺点,由于所有变量都能使用,容易使用错误的变量造成逻辑错误。
示例:通过改变联合体中其中一个变量的值,操作共享到其它变量:
/**
* @file 3union.c
* @author zoya (2314902703@qq.com)
* @brief 通过改变union中某一个变量的值来操作其它变量的改变
* @version 0.1
* @@date: 2022-10-09
*
* @copyright Copyright (c) 2022
*
*/
#include <stdio.h>
int main()
{
union
{
short nval;
char bval[2];
};
nval = 0x0102;
printf("联合体内存地址:0x%x\n", &nval);
printf("nval(0x%x) = 0x%04x, bval[0](0x%x) = 0x%02x, bval[1](0x%x) = 0x%02x\n", &nval, nval, &bval[0], bval[0], &bval[1], bval[1]);
bval[0] = 0x03;
printf("nval(0x%x) = 0x%04x, bval[0](0x%x) = 0x%02x, bval[1](0x%x) = 0x%02x\n", &nval, nval, &bval[0], bval[0], &bval[1], bval[1]);
return 0;
}
运行结果:
联合体内存地址:0x6427da16
nval(0x6427da16) = 0x0102, bval[0](0x6427da16) = 0x02, bval[1](0x6427da17) = 0x01
nval(0x6427da16) = 0x0103, bval[0](0x6427da16) = 0x03, bval[1](0x6427da17) = 0x01
因为测试机电脑是小段字节序的(高位数据存储在高位内存地址,低位数据存储在低位内存地址),bval[0]
所在的地址是低位内存地址(0x6427da16
),bval[1]
所在地址是高位内存地址(0x6427da17
),所以分别存储的是0x02
、0x01
。
根据运行结果可以看出来,改变其中一个变量,那么另一个变量也会对应改变。
4. 联合体union的应用
- 判断电脑字节序
根据联合体的这一特点,还可以判断电脑是小端字节序还是大端字节序,如下:
/**
* @file byteorder.c
* @author your name (you@domain.com)
* @brief 通过代码检测当前主机的字节序
* @version 0.1
* @date 2022-10-08
*
* @copyright Copyright (c) 2022
*
*/
#include <stdio.h>
int main()
{
union
{
short value; // 2字节
char bytes[sizeof(short)]; // 2字节数组
} test;
test.value = 0x0102;
if (0x01 == test.bytes[0] && 0x02 == test.bytes[1])
{
printf("大端字节序\n");
}
else if (0x02 == test.bytes[0] && 0x01 == test.bytes[1])
{
printf("小端字节序\n");
}
else
{
printf("未知\n");
}
}
寄存器读取
假设有一个I2C的温度控制寄存器,该寄存器是10位有效,需要读取该寄存器的值。但是I2C的数据传输是按照8bit的,每个时序只能接收8bit数据,只有使用char或unsigned char型接收数据,并且要接收2次。
传统的做法是声明一个char数组,包含2个元素,接收到数据后再通过计算给到一个short或int整数。
通过使用联合体也可以实现,使用联合体不用考虑各种转换问题,并且如果寄存器的有效位改变,也不用更改太多代码。
如下示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main()
{
// 传统的做法
char bval[2] = {0};
// 通过读取获取到寄存器的值,假设bval[0] = 02,bval[0] = 0x01
bval[0] = 0x02;
bval[1] = 0x07;
// 转换为整型
int nval = bval[0] | ((bval[1] & 0x03) << 8); // &0x03是因为10位有效
printf("nval = 0x%x\n", nval); // 使用联合体
union u1
{
int val;
char cval[sizeof(int)];
};
u1 tmp;
memset(&tmp, 0, sizeof(tmp));
tmp.cval[0] = 0x02;
tmp.cval[1] = 0x07; printf("val = 0x%x\n", tmp.val & 0x3ff); // &0x3ff是因为10位有效 // 寄存器的有效位改变,17位有效
tmp.cval[0] = 0x02;
tmp.cval[1] = 0x07;
tmp.cval[2] = 0x1f;
printf("val = 0x%x\n", tmp.val & 0x1ffff); // 0x1ffff是因为17位有效
}
程序运行:
nval = 0x302
val = 0x302
val = 0x10702
C/C++ union联合体介绍的更多相关文章
- union联合体使用详解
1.联合体联合体(union)与结构体(struct)有一些相似之处.但两者有本质上的不同.在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和.而在联合体中,各成员共享一段内存 ...
- (转)C语言union(联合体 共用体)
一直以来,union都是个很少用到的东西,对于这些不常用的结构往往记不住.这次看书又看到了,还是学习一下吧.一般在Windows API的一些数据结构中才能看到这个union,其实并不复杂.本质上来说 ...
- 转:union 联合体(共用体)
转自:http://blog.csdn.net/xiao3404/article/details/22276485 2.共用体 2.1共用体的概念 共用体是一种构造类型的数据结构.在一个“共用体”内可 ...
- C++基础之---union联合体大小分析
#include <iostream> using namespace std; union un { int a[7]; double b; char c[10]; int d[3]; ...
- union联合体学习
union,中文名“联合体.共用体”,在某种程度上类似结构体struct的一种数据结构,共用体(union)和结构体(struct)同样可以包含很多种数据类型和变量. 不过区别也挺明显: 结构体(st ...
- union联合体
今天笔试的一道题,好久没用union了,竟然忘光光了. 关于其大小的计算,分两步:先算对齐大小(成员中字节最大的那个),再算分配空间: 不仅是对齐大小的整数倍,还要满足实际大小不能小于最大成员大小. ...
- [C++]union联合体总结
特点一:成员公用内存,且按所占内存最大的数据成员分配内存 //举例1 union A{ char a;//1个字节 int b;//4个字节 char c;//1个字节 } cout<<s ...
- C++中联合体(union)的使用
typedef union para { ]; struct { double a; double b; double c; double d; }NP; }NPara; //或者如下所示 union ...
- 结构体struct、联合体union、枚举类型enum
1.c语言中的类型 1)内置类型——char,short,int,float,double: 2)用户自定义类型(UDT)——struct结构体,union联合体,enum枚举类型 2.内存对齐 2. ...
- 关于C中struct和union长度的详解
这几天看<代码大全>中的第十三章---不常见的数据类型,里面讲解到了C语言中的struct以及对指针的解释,联想到以前看过相关的关于C语言中stuct长度的文章,只是现在有些淡忘了,因此今 ...
随机推荐
- JSP第一次作业
1.环境搭建,运行出来一个JSP页面,显式hello <%@ page language="java" import="java.util.*" page ...
- NodeJS 实战系列:DevOps 尚未解决的问题
本文将通过展示 NodeJS 应用里环境变量的提取过程,来一窥 DevOps 技术是如何应用在现在云平台上的运维工作中的.同时我也想让大家在这里看到 DevOps 的另外一面,即它并非全能,从本地开发 ...
- W04 散文周刊 : 重回Emacs
W04 散文周刊 : 重回Emacs 邮箱:ppbhoy@qq.com 博客地址: www.pipihao.com 公纵号:南湖小皮 公告:后面会开始稳定更新 使用Emacs还是有些沉重,我一直将Em ...
- 2.3.pages.json文件的页面配置与全局配置
新建页面 # pages uni-app 通过 pages 节点配置应用由哪些页面组成,pages 节点接收一个数组,数组每个项都是一个对象,其属性值如下: 属性 类型 默认值 描述 path Str ...
- 2021级《JAVA语言程序设计》上机考试试题4
现在就是写学生,学生查看个人信息,,修改个人密码,学生功能页的页面,代码最一开始给了 然后,这三个比较紧密,所以一起写了 学生功能页 <%@ page language="java&q ...
- 合肥光源纵向震荡数据源相关PV的增补
合肥光源纵向震荡数据源相关PV 昨天发了上面那篇,对于那张二维纵向时间的图又做了些分析,因为要显示分析的结果,又增加了几个PV,说明如下: HLSII:BD:BCMSDS:Time:Spectrum ...
- Java 集合中的排序算法浅析
作者:京东物流 秦彪 1. 引言 排序是一个Java开发者,在日常开发过程中随处可见的开发内容,Java中有丰富的API可以调用使用.在Java语言中,作为集合工具类的排序方法,必定要做到通用.高效 ...
- B端业务中仓库标签打印系统设计方案
需求背景: 仓库在给客户货物打包途中需要在包裹上贴标签,在客户比较多且标签样式多样化的前提下,给仓库人员带来了工作量,为了节约仓库人员工作流程时间,公司开发了一套标签管理系统: 前提条件:选择专属打印 ...
- Training Spiking Neural Networks with Local Tandem Learning
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! 36th Conference on Neural Information Processing Systems (NeurIPS 202 ...
- 【KAWAKO】模型的压缩、扩张,计算模型的各种成本
目录 模型压缩 量化 稀疏化训练 剪枝 知识蒸馏 自蒸馏 集成 使用精细化模型结构 模型扩张 深度 宽度 输入图像的分辨率 深度.宽度.分辨率联合扩张 使用精细化模型结构 计算模型的各种成本 参数量 ...