
为什么要有内存对齐
- 首先我们要明白CPU不是我们想象中,想怎么样读取内存就可以怎么样读取内存的。
- 对于CPU来说,有可能一次读取2个字节,4个字节或8个字节,而且都是相当于0地址处来读取的。
- 举一个易懂的例子,假设一个double的数据从0地址开始存储,那么他的存储位置为0 1 2 3 4 5 6 7 。
如果CPU一次读取4个字节,那么从0地址处开始依次读4个字节,只需读取两步就可以。
如果double的数据从1地址开始存储,那么他的存储位置为1 2 3 4 5 6 7 8,则CPU需要先读取0 1 2 3,4 5 6 7,8 9 10 11。
读取三步才能读取到这个double的数据。
- 如果采用内存对齐,这个double的数据只会从0,4,8,12……这样的位置开始存储。
CPU可以从0,4,8,12……这样的位置直接开始读,因为CPU相当于0地址处一次读取4的字节刚好吻合。
- 所以结构体的内存对齐是拿空间来换取时间的做法。
当然还有其他的原因,比如平台原因,性能原因。
内存对齐规则
- 不管怎么声明结构体,第一个成员在与结构体变量偏移量为0的地址处开始存放。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的偏移量处。
- 对齐数=编译器默认的一个对齐数与该成员空间大小的较小值。
- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
最后,在设计结构体的时候,既要满足对齐,又要节省空间的方法是:让占用空间小的成员尽量集中在一起。
#pragma pack的使用与offsetof的模拟
1.
- #pragma pack(N)是用来修改编译器的默认对齐数。
- #pragma pack( )取消设置的默认对齐数,还原为默认。
- offsetof是用来计算结构体中某变量相对于首地址的偏移量。
- offsetof不是函数,而是一个#define定义的宏。
- offsetof(结构体名字,结构体成员名)返回的类型是size_t。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)