自定义类型:结构体
结构的声明:
例如:
在上面的例子中,Student 是结构体类型的名称,包含了三个成员变量:name(字符串类型)、age(整数类型)和 ID(整数类型)
结构体变量的创建和初始化
在使用结构体时,需要创建结构体变量并进行初始化。以下用利用代码和注释进行解释把,
匿名结构体类型
在声明结构的时候,可以不完全的声明。就是指在声明结构体变量时不给出结构体类型名称,直接定义结构体内部的成员。如图:
匿名的结构体类型如果没有对结构体类型重命名的话,基本上只能使用一次,因为没有为其命名,无法在其他地方再次引用相同的结构体类型。
结构体的自引用
结构体的自引用指的是在结构体定义中包含指向相同结构体类型的指针成员。
怎么用呢?比如,定义一个链表的节点:
看着好像没有问题,但这是一个错误的代码。因为一个结构体中再包含一个同类型的结构体变量,那sizeof(struct Nide)将会无穷大,是不合理的。
正确的自引用方式:
结构体中的内存对齐
结构体也是有内存大小的,这里就牵扯到一个重要的知识点:“结构体内存对齐”。也是很容易理解的。
对齐规则
在结构体里每个成员自身的对齐要求:
- char 类型的数据没有对齐要求,可以放在任意地址。
- short 类型一般需要2字节对齐。
- int 类型一般需要4字节对齐。
- long 类型一般需要4或8字节对齐,取决于平台(32位系统一般为4字节,64位系统一般为8字节)。
- float 类型一般需要4字节对齐。
- double 类型一般需要8字节对齐。
- 指针类型一般需要与平台的地址长度相同的对齐。
对齐数=编译器默认的一个对齐数与该成员变量大小的较小值。
VS中默认的值是 8
Linux 中 gcc 没有默认对齐数,对齐数就是成员自身的大小
整个结构体的对齐要求:
- 结构体的对齐要求是其内部成员中对齐要求最大的值。
- 结构体的起始地址一般是其对齐要求的倍数。
- 结构体的大小一般是其成员中占用空间最多的成员大小的倍数。
说人话就是结构体的总大小为对齐数(结构体中的每位成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。
有嵌套结构体的情况的话,嵌套结构体成员对齐到自己成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
基于以上的规则,我们幅图来明了一下:
为什么会存在内存对齐?
大部分的参考资料都是这样说的:
1.平台原因(移植原因):
不是所有硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则会抛出硬件异常。
2.性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次的内存访问;而对齐的内存仅需要一次访问。假设处理器总是从内存中读取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写了。否则,我们可能需要执行两次内存的访问,因为对象可能被分放在两个8字节内存块中。
总体来说:结构体的内存对齐是拿空间来换取时间的做法。
本期就到这里啦,欢迎一键三连,我们下期再见