拿捏结构体?别错过,重点在后面

1.声明,创建和初始化

2.自引用

3.重点:深入掌握结构体:内对齐规则及原因


1..结构体声明,创建和初始化:

性质:结构体是一些值的集合,这些值是成员变量,结构体内成员变量可以是不同类型的变量。

声明和创建:

声明:(普通声明和匿名声明)


 

以上均为普通类型的声明,那我可不可以声明的时候不声明类型呢?

答案是可以的,这种不完全声明的结构体叫做匿名结构体,但它有局限性,它只能够使用一次。

如下:

那这样写代码:p=&x;可不可以呢,答案是不行的。

编译器会将上面两个声明的类型看成是两个完全不同的类型。


初始化:(普通初始化和嵌套初始化)

普通初始化:两种

采用指针初始化:

嵌套初始化:

看完这个,有没有想过结构体自己嵌套自己的,其实那就叫自引用,这个等到我们下面再说。


结构体访问:

可以看到前两附图中我用到了(.)和(->),这两个是结构体访问操作符

(.):使用方法,结构体变量名 .成员名

(->):使用方法,结构体指针+成员名

这两种操作符具体该如何使用,通过下面这个图就足以让你理解。

<1.>:

<2.>:


2.结构体自引用:

就函数递归一样,函数自己调用自己。那结构体能不能自己引用自己呢?

下面这个代码是否可行:

这样自引用是不行的,你会发现sizeof计算字节大小是无穷尽的。

正确的自引用应该用指针更加适合,

在之前我们讲过typedef,其实在使用的过程中很容易错误使用typedef对结构体的重命名。

举个例子:

最保险的方法是:在结构体定义时不要使用匿名结构体。应该给结构体加上名字,这样就不存在匿名结构体了。

如下:

以上便是有关结构体基本知识了。

下面是对结构体的深入掌握。


3.深入掌握结构体:内对齐规则:

现在讨论一个深入的话题:如何计算结构体的大小?这就需要掌握结构体内对齐规则了。

这也是一个热门的考点:结构体内对齐规则

规则:

1.结构体第一个成员需要对齐到结构体变量起始位置偏移量为0的地址处。

2.其他成员变量要对齐到某个数字(对齐数)的整数倍地址处

对齐数:编译器默认的数字与该成员变量相比的较小值。

(不同的编译器默认值不同,vs默认为8,Linux中gcc没有默认对齐数,对齐数就是成员变量的大小。)

3.结构体的总体大小为最大对齐数(所有成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。

4.如果嵌套啦结构体,被嵌套的结构体需要对齐到自己成员变量中最大对齐数的整数倍处,结构体的大小就是最大对齐数的整数倍,这个最大对齐数需要包含被嵌套的结构体中最大对齐数

怎么样看到上面4条规则,是不是汗流浃背啦,

不用担心,跟着我看懂以下几道题目,相信你对上述4条规则有更好的理解。

练习一:

怎么回事?!明明这两个结构体成员变量的大小都一样,为字节大小却有所差距?

别急,现在开始理解规则

先看一幅图理解规则:

对于S1:规则3:结构体中字节最的为int,4个字节。所以4为结构体最大对齐数。

               规则1:第一个成员变量char对齐到偏移量0的地址处。

               规则 2:vs,默认对齐数为8,但int字节为4,取较小的4,要对齐到4的整数倍处,

               所以偏移量为1,2,3的均舍去,直接对齐偏移量为4处,int占4个字节

               char占1个字节,小于8,所以对齐数取1,此时偏移量已经对齐到8处,8是对齐数1倍数,所以这个char对齐到8处

                最后这个总体大小为9,但9并不是最大对齐数4的倍数,所以要浪费3个字节,使结构体占12个字节才能是4的倍数。

对于S2:

规则3:结构体中int占有的字节最大,所以最大对齐数为4;

规则1:第一个成员变量需要对齐到偏移量为0的地址处,所以第一个char对齐0

规则2:其他成员变量需要对齐到对齐数的整数倍处,第二变量char占有1个字节,小于8,取对齐               数为1,因为1是1的倍数,所以第二个char对齐到1处

接下来到成员变量int对齐了,因为从偏移量2不是4的倍数,4是4的倍数,所以要舍弃两个字节,对齐到偏移量为4处,int占4字节,所以到7处结束

规则3:因为从0到7,结构体大小为8,8是最大对齐数的整数倍,最终结构体大小取8.

总结:这里S1浪费6字节,S2浪费2字节,所以一个结构体的大小与其内部成员变量的排序有很大关系。

为了能够完全掌握再来两题:

分析图:

S3:

分析:

对于S3:成员变量最大double占有8个字节,最大对齐数8

第一个·成员变量对准0偏移量处,一直到7

第二个成员变量char为1字节,8为1的倍数,所以对准8处

第三个int型4字节,9,10,11均不是4的倍数,所以向下找到12为4的倍数,那么9,10,11均被浪费

结构体一共占有16个字节,是最大对齐数8的倍数,所以结构体一共16字节。

S4:

分析:

char占一个字节,对齐偏移量为0处

S4:

中最大字节数struct s3 占有16个字节,所以最大对齐数为16

double占16个字节大于默认对齐数8个字节,取小的8,向下移动找到偏移量8处,占有16个字节,到23处。

第三个变量,double类型为8个字节,正好为8,向下找8个到31处

最后结构体总大小为32,是最大对齐数16的倍数

中间浪费7字节。

4.内对齐原因:

1.不是所有硬件平台都能访问任意地址上的任意数据,某些平台只能访问特定地址的数据,所以要内对齐使数据存储的有规律。

2.对于栈内的数据,如果数据分布不在边界上,处理器需要做两次访问,而对齐的数据只需要一次访问便可以读取全部,假设⼀个处理器总是从内存中取8个字节,则地 址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以 ⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两 个8字节内存块中。

总结:结构体内对齐就是用空间换取时间的方法

  • 31
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值