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字节内存块中。
总结:结构体内对齐就是用空间换取时间的方法