目录
结构体内存对齐的规则:
为什么存在内存对齐?
修改默认对齐数
在计算结构体的大小时,我们用下面常规思想进行计算
我们知道,char型和int型在内存中分别占用1个字节和4个字节,结构体S1中有2个char型和一个int型数据,S1占用内存应该为6个字节才对,但是却占用了12个字节,在结构体S2中数据只是换了顺序,占用内存又变成了8个字节,这是怎么回事呢?在计算结构体大小时,我们要了解一个新的知识点:结构体内存对齐
在对结构体大小进行计算时,我们首先了解一个宏:offsetof() 用于结构体成员相较于结构体起始位置的偏移量 使用时需要添加头文件 #include
用offsetof()计算下S1中各结构成员的偏移量
我们发现,c1、i、c2相较于结构体起始位置的偏移量分别是0、4、8
作图
上面的现象分析,我们发现,结构体成员倍数按照顺序在内存中连续存放的,而是有一定的对齐规则
- 结构体的第一个成员永远放在相较于结构体变量起始位置的偏移量为0的位置
- 从第二个成员开始,往后的每个成员都要对齐到某个对齐数的整数倍处。对齐数:结构体成员自身的大小和默认对齐数的较小值。 VS上默认对齐数是8。 gcc(Linux)没有默认对齐数,对齐数就是结构体成员的自身大小。
- 结构体的总大小,必须是最大对齐数的整数倍。 最大对齐数是:所有成员的对齐数中最大的值。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
根据对齐规则,我们可以知道各结构成员在内存中的对齐方式,以及结构体的大小
分析下面结构体大小
作图(注:double类型的大小为8个字节)
结构体内嵌套结构体
作图分析(嵌套结构体对齐到其自身最大对齐数的整数倍处)
1. 平台原因 ( 移植原因 ) :不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。2. 性能原因 :数据结构 ( 尤其是栈 ) 应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
数据结构角度上对内存对齐的分析
结构体的内存对齐是拿 空间来换取时间 的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。
在下面例子中,S1,S2类型成员一模一样,但是S1,S2所占空间的大小有了一些区别。
分别对结构体S1、S2的大小作图分析
#prama 这个预处理指令,可以修改我们的默认对齐数。
使用方法:
#pragma pack(8)//设置默认对齐数为8
........
#pragma pack()//取消设置的默认对齐数,还原为默认
例如将默认对齐数设置为2,于默认对齐数为8时结构体的大小的对比
作图分析不同默认对齐数对结构体大小的影响
结构在对齐方式不合适的时候,我们可以自己更改默认对齐数。注:默认对齐数最好设置为2的倍数,不然在节省内存空间方面反而会适得其反。