龙空技术网

C语言学习篇(23)——共用体union

嵌入式笔记v 7164

前言:

此刻姐妹们对“c语言double的用法与搭配”都比较着重,大家都需要知道一些“c语言double的用法与搭配”的相关资讯。那么小编同时在网络上网罗了一些对于“c语言double的用法与搭配””的相关知识,希望咱们能喜欢,大家快快来学习一下吧!

引言

在C语言中,每个数据类型都有其特定的作用或使用场景。 前面我们详细的分析了数组,结构体,今天我们来讲讲共用体(union),所谓的共用体就是使用覆盖技术让数据成员之间相互覆盖,以实现不同数据成员共用同一段内存。先引出概念,接下来我们从共用体与其他的数据类型区别,到共用体类型如何定义,哪些场景会使用共用体等等,逐步分析。

共用体和结构体区别

共用体(union)和结构体(struct)在类型定义, 变量定义,使用方法上都非常相似:

//共用体类型定义union test{	int a	char b;};

变量的定义和使用:

//定义共用体变量t1	union test t1;	//使用共同体t1成员	t1.a = 23;	

那两者有什么区别呢?结构体好比是一个袋子,袋子里面装了各种各样的东西,每个东西都是独立存在的,占据了袋子体积; 而共用体的各个成员是一体的,彼此不独立,它们使用同一块内存空间,可以理解为:有时候是这个元素,有时候是另外一个元素(就像是一个多面人),有不同的形态,更准确的说是同一块内存空间有多种解释方式!通过以下示意图感受下:

接下来我们通过实例代码,来理解其本质区别:

#include <stdio.h>//定义结构体类型struct test1{	int a;	char b;};//定义共用体类型union test2{	int a;	char b;};int main(void){   //定义结构体变量t1	struct test1 t1;  //定义共用体变量2	union test2 t2;		t1.a = 23;	t2.a = 24;	  //打印变量元素	printf("t1.b = %d.\n", t1.b);	printf("t2.b = %d.\n", t2.b);//打印结构体t1元素的地址  printf("&t1.a = %p.\n", &t1.a);	printf("&t1.b = %p.\n", &t1.b);	//打印共用体t2元素地址	printf("&t2.a = %p.\n", &t2.a);	printf("&t2.b = %p.\n", &t2.b);		return 0;}

说明:

1.我们分别定义了结构体变量t1, 和共用体变量t2

2. 初始化了结构体t1中的元素a, 赋值为23,但是元素b未初始化

3. 初始化了共用体t2中的元素a, 赋值为24,同样元素b未初始化

4. 之后我们分别打印了t1和t2成员的地址

接下来我们编译运行,看下结果:

可以看到结构体t1的元素b未初始化,是一个随机值(因为我们定义的t1是局部变量,定义在栈上,如果不清楚什么是栈,什么是堆,以及它们的特性,可以查阅我之前的文章~)。

而共用体t2元素b未初始化, 但是它的值与元素a居然相同(这不是凑巧哦,不相信的小伙伴可以自己测试下,当然前提是a的初始化的值不能超过元素b的类型值域, 同时这里会涉及大小端的问题,这个之后会详细分析)。同时可以看到结构体t1的元素a和b的地址是不同的, 而共用体t2的元素a和b地址是完全一致!相信到这里大家能基本了解了共用体的特性: 成员之间共用一块内存空间,只是解析方式不同。

共用体的大小

经过上面的讲述,大家知道了共用体的成员其实是共享了一块内存空间,哪么当我们顶一个共用体类型时,它实际占用的内存空间是多少呢?

我们先举一个简单的例子:

#include <stdio.h>union test{	int a;	char b;	};int main(void){	union test t1;	   //打印共用体成员的数据类型大小	printf("sizeof(int) = %d.\n", sizeof(int));	printf("sizeof(char) = %d.\n", sizeof(char));	//打印共用体大小	printf("sizeof(union test) = %d.\n", sizeof(union test));		return 0;}

编译运行结果:

可以看到共用体变量t1的内存大小为4字节, 即原则上,共用体大小取决于占据最多内存的成员的长度。需要注意这里用的“原则”一词,因为有时候需要考虑内存对齐问题。 我们通过以下例子来加深理解:

#include <stdio.h>//通过__attribute__指令设置1字节对齐__attribute__((aligned(1)))struct mystruct{	char a;	int b;	int c;	int d;	int e;	double f;	char g;	short h;	double i;	float j;	}__attribute__((packed));//通过__attribute__指令设置1字节对齐__attribute__((aligned(1)))union test{	int a;	char b;	float c;	double d;		struct mystruct my1;}__attribute__((packed));int main(void){//定义了共用体变量t1	union test t1;	  //打印了结构体大小	printf("sizeof(struct mystruct) = %d.\n", sizeof(struct mystruct));//打印共用体大小	printf("sizeof(union test) = %d.\n", sizeof(union test));		return 0;}

分析:

1. 首先我们定义了结构体类型mystruct, 并使用__attribute__指令设置为1字节对齐

2. 定义了共用体类型,其中一个成员是上面定义的结构体mystruct类型, 同时也使用__attribute__指令设置为1字节对齐

3. 定义了共用体变量t1

4. 分别打印了结构体mystruct类型大小,和共用体test 类型大小

OK, 编译运行:

我们可以看到共用体的大小就等于成员my1(结构体类型)的大小,再次验证了上面的结论。

共用体的访问方式

上面我们举得的例子都是使用下标式访问共用体成员,还是和数组,结构体一样, 下标式访问知识编译器提供的一种语法糖, 方便开发人员使用和理解, 但是我们需要了解其本质: 共享一块内存,只是解析方式不同。 因此我们可以通过指针方式来访问,这也是真正理解共用体的判断标准。

#include <stdio.h>union test{	int a;	float b;};int main(void){	union test t1;	  //下标式访问	t1.a = 1123477094;	printf("t1.b = %f.\n", t1.b);	 //指针式访问	int a = 1123477094;	printf("指针方式: t1.b = %f.\n", *(float *)&a);		return 0;}

编译运行:

从结果再次验证共用体实质:共享一块内存,只是解析方式不同。

总结

通过以上分析,我们了解了共用体的实质,如何定义和使用,以及与结构体的区别等。 之后我会讲解共用体的应用场景,尤其是如何使用共用体测试系统大小端,这也是面试和笔试中出现的概率非常高的题目,如果你对大小端的概念不是很清楚,或者想了解有哪些办法测试系统的大小端,欢迎转发,收藏,关注,后续内容更加精彩哟~

标签: #c语言double的用法与搭配