28 结构体的进阶1

在结构体初阶的时候学习了结构体的声明和初始化,我们知道,声明相当于给了一个建筑图纸,知道结构体要怎么建立、包含哪些类型,此时并没有在内存中开辟空间,而当初始化的时候,才算用这个图纸盖了一栋房子,在内存中开辟了空间

然后学习了两种访问成员的方法以及结构体传参,今天学习结构体的自引用和内存对齐

1、结构体的自引用

在数据存储的时候,有两种存储方式,一个是顺序存储结构一个是链式存储结构

顺序存储结构就是数据从低地址到高地址连续存储

那如果我们不想顺序存储呢,那只能打乱顺序排放存储,但是我们又想在找到其中一个的时候找到下一个,那这时候就需要用到链式存储结构

f614323f5c224848b26c3f922b5028fe.jpg

382ef4351196474eb68ba61a422a14ee.jpg

 代码实现:

d0b140b56c6c4dfb8f1081a43db66b33.jpg

注意:第一种写法是错误的,因为结构体嵌套自己本身时,无法计算该结构体的大小,会不断的引用自身导致程序崩溃(相当于递归没有终止条件)

而且我们在上面也说过链式存储结构要包含下一个数据的地址,所以这里要用指针(指针的大小就可以计算了)

8b372e44ab044e31b6cd3cf9eb9ffecc.jpg

第一种代码不可行,因为在结构体声明的时候没有写出struct tag中的tag(结构体标签),所以这个代码是非法的

1/3日更新

第一种不可行的原因是在还没有重新定义名字的时候就使用了Node,所以才不可行,并不是说tag省略就错了

第二种代码是重新定义类型:

typedef意思是把这个结构体重新定义了一个新的名字,以后想用它那么:

struct Node n;

Node n2;

就是一个意思了

2、内存对齐

当知道了结构体的基本使用之后,那我们应该考虑一个问题,结构体的大小应该如何计算?

65e78dbeb2cd4d1ba25f38ba45dff2ca.jpg

s1大小是12,s2大小是8

仅仅只是结构体里面换个顺序,为什么大小会不一样呢?

这里要介绍一个规则:内存对齐

8e975423794b4fe3bd81edca6c46c74b.jpg

根据对齐规则一个一个看:

1.什么是偏移量

75ba134b667e43ac91f4e26ce9731401.jpg

以s1举例:当确定了s1在某个地址处开始时,它的第一个内存块就是偏移量为0的地址,第二个内存块是偏移量为1的地址,以此类推

2、对齐数

s1第一个成员放完之后,占用了偏移量为0的内存块,然后开始放第二个成员,从第二个开始就要考虑对齐数,根据规则,第二个成员的对齐数为4

那么4的整数倍是4、8、12等等,所以第二个成员要从偏移量为4的内存块开始(绿色部分)

接着看第三个成员,它的对齐数是1,也就是哪里都能放,所以直接放在第二个成员后面就行,此时结构体总大小应该是9个字节

3、结构体总大小

全部成员放完之后并不算结束,还要检查结构体的总大小,我们知道s1最大对齐数是4,所以结构体的总大小应该是4、8、12、16等等,所以我们要把s1的总大小修正为12

4、嵌套结构体的大小计算

9bf85297704241508329e11d91914fd5.jpg

根据上述规则计算s3:

double的大小8字节,从偏移量为0的内存块开始存放,连续存放八个字节;

char的大小1字节,对齐数是1,直接在偏移量为8的内存块存放,占一个字节;

int的大小4字节,对齐数是4,此时只能从偏移量为9的内存块存放,所以要对齐到偏移量为12的内存块,存放4个字节,此时存放到了偏移量为15的内存块,大小为16字节

检查,s3最大对齐数是8,16是8的整数倍,所以该结构体总大小是16字节

然后再来看s4的嵌套结构体大小

char大小1字节,在偏移量为0的内存块;

结构体s3的最大对齐数是8,所以要放在偏移量为8的内存块,连续存放16个字节,此时最后存放的在偏移量为23的内存块;

double对齐数是8,存放在偏移量为24的内存块中,连续存放8个字节,此时最后偏移量为31

所有最大对齐数是8,32字节符合要求,所以s4的大小是8

为什么存在内存对齐?

内存对齐会浪费空间,那为啥还要这样做呢?

1.平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些定类型的数据,否则抛出硬件异常

2.性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问

总的来说:

结构体的内存对齐就是拿空间时间的做法

22291b47006349d1902731d2a028bbe0.jpg

 

 

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值