前言
最近的项目中经常要用到共用体这种数据结构,但自己动手去写的时候,心里又毛毛的,好像还并没有完全掌握它。因此写下这篇文章,对这个知识点进行一次归纳整理,后续有想到新东西,再来补充。
union是啥?和共用体是啥关系?
union只是一个关键字,它是用来构成一种全新的变量类型的。这个关键字不能直接与像是int、char这样的关键字进行类比。因为像是char、int这样的关键字表示的就是一种变量类型,它们有确定的内存空间,而与它们相比,union这个关键字并不能明确出一个内存空间,它还需要一些“伙伴”才能明确出要占用多少空间。这些“伙伴”在C语言中我们称之为–成员。union关键字与它的成员结合在一起,构成了新的变量类型,这种新的变量类型,叫做共用体(联合体、联合类型),这个共用体才是能与int、char等关键字平起平坐的。
创建一个共用体
创建共用体的意义就是告诉计算机你所规定的一种新的变量类型,这个过程不会开辟内存空间,也没有变量的概念。创建共用体有如下两种方法:
1.直接创建
union my_type
{
unsigned char mem1; //成员1
unsigned int mem2; //成员2
float mem3; //成员3
};
2.用typedef
typedef union
{
unsigned char mem1; //成员1
unsigned int mem2; //成员2
float mem3; //成员3
}my_type;
共用体创建的这几行代码可以按照char、int关键字来理解,下面定义的环节会更形象。
定义一个共用体类型的变量
那么如何才能使用一个共用体类型的变量呢?那就需要去定义一个共用体变量了,方法有如下3种:
1.基于直接创建的共用体类型
//1.直接创建一个共用体
union my_type
{
unsigned char mem1; //成员1
unsigned int mem2; //成员2
float mem3; //成员3
};
//2.定义一个共用体变量variable1
union my_type variable1;
2.基于用typedef创建的共用体
//1.用typedef创建一个共用体
typedef union
{
unsigned char mem1; //成员1
unsigned int mem2; //成员2
float mem3; //成员3
}my_type;
//2.定义一个共用体变量variable1
my_type variable1;
3.创建与定义同步进行,包含两种方式
//1.不写共用体名称
union
{
unsigned char mem1; //成员1
unsigned int mem2; //成员2
float mem3; //成员3
}variable1; //定义一个共用体变量variable1
//2.写共用体名称
union my_type
{
unsigned char mem1; //成员1
unsigned int mem2; //成员2
float mem3; //成员3
}variable1; //定义一个共用体变量variable1
以上三个例子中,my_type叫做所创建的共用体的名称(与共用体变量无关),mem1,mem2,mem3为其成员。而variable1为一个共用体变量。
共用体内存空间
这里可以与结构体进行比较,如果把结构体想象为一个小团体,里面就会有小明、小红、小芳等成员,那么共用体更像是一位“人格分裂症患者”,它有时候是小明,有时候是小红,有时候是小芳。本质在于共用体的内部变量占用的是同一块内存空间,由于是同一块内存空间,所以各个变量之间会有相互影响,所以在使用时,要注意使用场景。
共用体使用
我个人使用的场景种类不多,但是用法相对固定,将联合体与结构体以及位域结合使用,构成一种部分与整体联系很紧密的数据结构。比如说在控制多个继电器时,用位域与联合体结合使用,可以达到节省空间,掌控某个以及全部继电器的效果,示例如下:
//1.创建一个共用体
typedef union
{
unsigned char relay_all;
struct
{
unsigned char relay_0:1;
unsigned char relay_1:1;
unsigned char relay_2:1;
unsigned char relay_3:1;
unsigned char relay_4:1;
unsigned char relay_5:1;
unsigned char relay_6:1;
unsigned char relay_7:1;
}realy_single;
}u_realy_tpye;
//2.定义一个共用体变量
u_realy_type my_relay;//尚未初始化
解释一下这个my_relay这个变量,看起来也许有些复杂,没关系,一层层分析就好,2层的小套娃而已。
1.明确my_relay这个变量是一个共用体类型的。
2.这个共用体类型包含了两个成员:无符号字符型变量relay_all以及结构体类型变量realy_single。
3.无符号字符型好理解,重点剖析这个结构体类型的变量,此结构体包含了8个1位位域的无符号字符型变量,整个结构体的内存空间就是8位,也就是1个字节。
4.再回归到这个共用体类型,其包含的两个成员所占空间都是1个字节,是完全共用的空间,所以这个共用体类型所占空间也是1个字节。
tips.定义了my_relay这个变量后,基于它的结构,便可以很方便的控制这个变量所占内存空间的8个位中的任意一位以及整个字节。
共用体初始化
沿用上一部分的例子,来给my_relay进行初始化。
由于共用体的成员共享同一块内存空间,所以修改某一成员的值时,其它值也就决定了且各个成员间会彼此影响,因此共用体的初始化比较特殊:在初始化时,不能同时对所有成员进行初始化。有如下三种初始化手段:
1.默认初始化第一个成员:
u_realy_type my_relay = {0};
具体来讲,此种初始化会将共用体变量中的第一个成员,也就是relay_all这个变量给赋值为0,当然,由于两成员内存空间完全重叠,因此结构体变量realy_single中的每一个位成员变量也都是0。
2.直接用一个共用体初始化另一个共用体:
u_realy_type my_relay = {0}; //以第一种方式初始化的共用体 u_realy_type my_relay1 = my_relay; //这个才是要介绍的以第二种方式就行的初始化
3.指定初始化成员(C99新特性)
u_realy_type my_relay = {.relay_all = 0};//由于楼主主要进行的是单片机开发,编译环境是MDK,这种方式总是报错,应该是我的编译环境不支持
以上就是共用体的三种初始化方式,我一般只用第一种,了解这种初始化方式后,会让你对成员变量的顺序安排上有更多思考~
总结
本文详细的介绍了union、共用体(联合体、联合类型)间的区别与联系,通过实例的方式对共用体类型的创建、定义以及初始化进行了讲解,以达到读者可以快速上手共用体的目的!
如果本文对你有用,请点个赞吧,这是对我莫大的支持,当然也更欢迎评论区留言讨论以及收藏哦~
祝:变得更强!