ios 结构体大小端转换_C语言学习篇(23)——共用体union

引言

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

共用体和结构体区别

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

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

变量的定义和使用:

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

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

730f6ed3504186af2b40ba834bd60d14.png

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

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

说明:

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

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

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

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

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

ffcb89b7b7febdffaf6faa4c3e977e57.png

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

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

共用体的大小

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

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

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

编译运行结果:

0b3a9a544772eaa64e153af7223810d9.png

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

#include //通过__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){//定义了共用体变量t1union test t1;  //打印了结构体大小printf("sizeof(struct mystruct) = %d.", sizeof(struct mystruct));//打印共用体大小printf("sizeof(union test) = %d.", sizeof(union test));return 0;}

分析:

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

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

3. 定义了共用体变量t1

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

OK, 编译运行:

f961e2d4f61c1683bf79a8eed0a373f9.png

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

共用体的访问方式

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

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

编译运行:

988423c79931cf2ad638f2539f1bec8f.png

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

总结

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

2e53203bfb9270ba42ab96ef1bf3ad05.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值