前言:Hello大家好,我是@每天都要敲代码!今天就带大家学习一下新的内容;三大自定义类型:结构体struct,枚举enum,联合union;看着内容很少,其实知识点也很丰富;希望下面我的讲解能让大家有所收获!
1. 结构体
1.1 结构的基础知识和声明
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。我们需要掌握:结构体类型的声明、结构的自引用、结构体变量的定义和初始化、结构体内存对齐、结构体传参、结构体实现位段(位段的填充&可移植性)!
回顾:数组是一组相同类型的元素的集合!
对于结构体的声明,我们就拿一个例子来解释;更加的容易理解:
❤️例:
1.2 匿名结构体的声明
匿名结构体的声明是指在声明结构的时候,可以不完全的声明!还是不明白什么意思?我们不妨拿个例子来理解:
❤️例:
1.3 结构的自引用
❤️1、一个结构体引用另一个结构体
一个结构体引用另一个结构体是完全没问题的!
❤️2、自己的结构体引用自己
结构体里面,自己引用自己,会造成死循环;相当于死递归,是错误的引用!
❤️3、正确的自引用方法
一个结构体不是包含同类型结构体的变量,而是包含同类型结构体的指针,是完全没问题的!
1.4 结构体变量的初始化和打印
❤️例:
1.5 结构体内存对齐(结构体大小的计算)
首先先介绍一下对齐规则:
(1)第一个成员在与结构体变量偏移量为0的地址处。
(2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的值为8
(3)结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
(4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
tips:一定要先理解上面的四句话,在进行习题的练习!
❤️例题1:
⭐️对于结构体S:
(1) c1放在偏移量为0处,且占一个字节!
(2)i占4个字节,直接从偏移量为1处开始?当然不是!其他成员变量要对齐到某个(对齐数)的整数倍的地址处。对齐数 = VS中默认的值为8与 该成员大小的较小值。所以对齐数应该是4,应该从4的倍数开始,要舍去1、2、3这三个字节!最终从4开始:4、5、6、7;如下图:
(3)最终结构体的大小,也要是这个结构体成员变量的对齐数最大值的整数倍!这里也就是4的倍数;结合(2)最终结果就是8!
⭐️对于结构体S2:
(1)c1放在偏移量为0处,且占一个字节!
(2)i占4个字节,直接从偏移量为1处开始?当然不是!其他成员变量要对齐到某个(对齐数)的整数倍的地址处。对齐数 = VS中默认的值为8与 该成员大小的较小值。所以对齐数应该是4,应该从4的倍数开始,要舍去1、2、3这三个字节!最终从4开始:4、5、6、7;
(3)c2占一个字节,对齐数 = VS中默认的值为8与 该成员大小的较小值。所以对齐数应该是1;刚好放到8的位置;如下图:
(4)(3)最终结构体的大小,也要是这个结构体成员变量的对齐数最大值的整数倍!这里也就是4的倍数;结合(2)(3)最终结果就是:12;而不是9(9不是4的倍数);所以最终还是会浪费3个字节9、10、11!
❤️例题2:
⭐️对于结构体S:
通过画图我们知道,S的大小应该是9,但是9却不是4的倍数;所以最终结果就是12!
⭐️对于结构体S2:
通过画图我们知道,S2的大小应该是16,16刚好是4的倍数;所以最终结果就是16!
⭐️对于结构体S3:
通过画图我们知道,S3的大小应该是8,8刚好是4的倍数;所以最终结果就是8!
⭐️对于结构体S4:
通过画图我们知道,S4的大小应该是16,16刚好是8的倍数;所以最终结果就是16!
⭐️对于结构体S5:
对于结构体S5;里面嵌套着结构体S4;首先是c1在偏移量0处,且占1个字节!然后是结构体S4我们已经计算出来是16字节的大小;这就占17个字节就是0-16,下一个位就是17开始;最后d占8个字节,17不是8的倍数,应从8的倍数24开始,数8个就是到31;所以最终结果就是32!
补充:
(1)在设计结构体的时候,既要满足对齐,也要节省空间,怎么做到?
答:让占用空间小的成员尽量集中到一起!
(2)为什么存在内存对齐?
答:1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。