结构体和联合体的存储

今天我们来看看结构体和联合体的存储,新的一天,卯足精神,冲冲冲!!!

目录

结构体的存储

偏移量,对齐数,默认对齐数

方法一:将相同类型的成员都放在一起

方法二:使用位段

位段的跨平台问题

位段使用的注意事项

联合体的存储

总结


结构体的存储

我们已经了解了整型类型,浮点数,字符数的存储,我们来了解一下结构体的存储,要知道结构体的存储和它们的存储方式截然不同,而结构体是什么呢?简单来说是一个能一下定义多个数据类型的结构,简单来说,当我们想一下定义多个变量时,结构体就当仁不让了,比如我们要记录一个学生的基本信息(学号,姓名,性别,成绩等等),我们就能使用它,我们一起来看看:

而另一个问题出来了,我们知道整型类型为4个字节,这里的字符数组占10个字节,这里的整型数组为12个字节,那就有很多同学就认定有16个字节(4+10+12),那它这个结构体是不是就时有16个字节呢?我们看看:

很显然,并不是16个字节,而是28个字节,那它到底是怎么存储的呢?首先我们要引入偏移量,对齐数,默认对齐数的概念。

偏移量,对齐数,默认对齐数

我们先来来了解对齐数,默认对齐数的概念。默认对齐数根据编译器不同,默认对齐数也就不同(根据编译器不同而不同),(Linux中gcc没有默认对齐数,对齐数就是成员本身大小)以vs2022为例,默认对齐数是8个字节,从上到下它们各自的字节大小分别为4,1,4,而它们各自字节大小和默认对齐数相比,哪个小,就取哪个作为它们各自的对齐数大小,得到了它们各自的对齐数大小后,就开始存放,从偏移量为0时开始存放,如果偏移量不是它们各自对齐数的倍数,那么偏移量向后移,直到为各自对齐数的倍数,然后再开始存放,将所有成员全部存放好之后,如果此时的结构体大小不是各自成员当中最大对齐数的倍数,那么此时结构体大小扩大,直到结构体大小时当中最大对齐数的倍数,此时结构体大小就确定下来了。这么说的话,是不是难以理解?我们上图:

这样看是不是茅塞顿开了?那如果结构体嵌套呢?那有该如何计算结构体大小呢呢?

怎么样?你算对了吗?我们一起来分析一下(记得参考上图):

现在,是不是对结构体有了独到的见解?并且是不是又有了新的问题?将一个结构体存好,有时候它十分浪费内存,中间空着的内存它没东西存进去,是不是十分浪费?那么有什么办法才能节省一下内存?

方法一:将相同类型的成员都放在一起

我们来体会一下:

是不是节省了不少?我们接下来看看第二种方法。

方法二:使用位段

什么是位段呢?怎么使用呢?位段其实就是限制每个成员存放的比特位,在成员变量名之后加个冒号再输你想保存的多少个比特位。我们要知道位段其实是专门来节省内存的。

那么这样的结构体是怎么来存的呢?(以上面那个结构体为例)先开辟一个字节的内存(8个比特位),然后开始存放a的数据(只存3个比特位),然后剩下的比特位继续存下一个成员数据。那么这样存放的话,就会出现两个问题,一是开辟了一个字节之后,是从左到右开始存放还是从右到左开始存放呢?很遗憾c语言标准并没有规定,所以怎么存放是根据编译器来定的。二是当继续存放下一个数据时,如果不够,剩下的比特位是浪费呢?还是继续使用呢?而我们现在以vs2022为例,开辟空间后从右向左使用,不够的比特位直接浪费掉。而当我们存储数据的时候,如果提供的比特位不够存的话,就会发生截断。我们上图理解看看:

我们上图验证一下:

那么最终这个结构体也是只占了2个字节。虽然位段能节省不少内存,但也存在很多问题。

位段的跨平台问题

首先就是int类型被当成有符号类型还是无符号类型,这个不确定(根据编译器)。其次是从左向右还是从右向左开始存储,c语言标准没有定义。再次是当存下一个成员时,不够存的话,剩下的空间是浪费还是继续使用,这个未知。最后就是位段中最大位的数目不能确定(早期是有16位机器的,16位机器上int类型是2个字节,32和64位机器上int类型是4个字节),有可能会出问题,比如我要这个数据的20个比特位,但此时在16位机器上int类型只有16个比特位,那么我这个数据从哪里开始存呢?而且也不够存啊。

位段使用的注意事项

使用了位段之后,尽量少用甚至不用&符号,因为每个字节是有地址的,但有些成员数据是在比特位里面的,而比特位是没有地址的。

联合体的存储

联合体和结构不同,结构体是每个成员都有一个"房子",而联合体不同,它是里面的每个成员都共用一个"房子",我们来刨析一下:

我们不难发现三者的地址都是一样的,也就是说里面成员的存储共用了。因此联合体也叫共用体。我们上图理解理解:

这样看,就有很多人觉得联合体的大小就是它当中最大存储字节的那个成员大小。其实不然,我们来看看这样一个联合体:

大多数人以为是5,而结果却是8。我们来说仔细分析一下:一般来说联合体的大小最小也要是它成员当中占最大字节的大小。而联合体大小也要和结构体大小一样,最终要满足其成员最大对齐数的倍数。以上图这个联合体为例,最终联合体的大小要是4(最大对齐数)的倍数,最终为8。

总结

我们只要了解它其中的知识点和逻辑,将其理清并梳理好,我们才能将其为自己所用。理解了结构体和联合体,我们又强大了一点点。向前冲!!!

  • 64
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
在C/C++编程中,结构体(struct)和联合体(union)都是用来组合不同类型的数据成员,但它们的用途和行为有所不同。 **结构体(Struct)**: - 结构体是一种用户自定义的数据类型,它可以包含不同类型和数量的数据成员。 - 每个结构体变量占有独立的内存空间,每个数据成员有自己的地址,即使它们的类型不同。 - 结构体通常用于表示具有多个相关属性或组件的实体,如一个人的信息(姓名、年龄、性别等)。 **联合体(Union)**: - 联合体同样可以包含不同类型的数据成员,但所有成员共享同一块内存空间,即只有一个成员在任何时候是有效的。 - 当一个联合体变量被初始化时,只有其中的一个数据成员会被占用,其他成员则会被清除为默认值。 - 联合体常用于存储大小不确定的数据,例如不同类型的测量值,因为它们只需要足够的空间来存储当前被选中的类型。 当结构体联合体结合使用时,可能会有这样的情况: 1. 结构体中包含了联合体作为其中一个成员,这样可以在更大的结构中嵌套更小的灵活性。 2. 有时联合体可以用作结构体的一个特殊成员,提供一种动态选择存储类型的能力。 3. 结构体联合体可以共同实现数据压缩或者简化内存管理。 **相关问题**: 1. 结构体联合体的主要区别是什么? 2. 联合体如何处理内存空间? 3. 结构体中嵌套联合体的例子是什么? 4. 在什么情况下会选择使用联合体而不是结构体
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值