要了解内存对齐的规则,首先我们要先知道什么是内存对齐。
内存字节对齐的概念:
计算机中内存空间是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是:在访问特定类型变量的时候通常在特定的内存地址访问,这就需要对这些数据在内存中存放的位置有限制,各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
内存对齐是编译器的管辖范围。表现为:编译器为程序中的每个“数据单元”安排在适当的位置上。
内存对齐的好处
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取,而不是内存中任意地址都是可以读取的。
比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。
所以在访问一些数据时,对于访问未对齐的内存,处理器可能需要进行多次访问;而对于对齐的内存,只需要访问一次就可以。对齐不仅便于CPU快速访问,同时合理的利用字节对齐可以有效地节省存储空间。
数据类型的大小规则
因为内存对齐要求各种数据类型按照一定的规则排列,那么我们就最少需要知道各种数据类型在32位和64位操作系统下的大小规则,如下图:

内存字节对齐规则
一:结构体中的元素是按照定义的顺序一个一个放到内存中去的,不是我们想的紧密排列的那样。从结构体存储的首地址开始,每个元素放到内存中时,都是以当前元素的大小来划分的,因此放置的起始地址一定要是当前元素的整数倍上。
二:当按照规则一计算出总长度后,需要判断这个总长度是否是 struct 中最宽元素的长度 n 的整数倍。如果不满足,则要补齐为最宽长度 n 的整数倍。
三:如果 struct A 中含包含 struct B 元素,则 struct B 的起始地址必须是 struct B 中的最宽元素的整数倍。
下面我们结合这几点规则来看几个案例
typedef struct {
char a;
int b;
char c;
double d;
} AStruct;
sizeof(AStruct) = 24

按照上面的大小规则,a是char型,大小为1,所以在位置0,b为int,长度为 4 个字节,按照规则一,所以b要从位置4开始,占据4,5,6,7四个位置,c在位置8,d长度为8个字节,所以就要从16开始,占据16~23,这是总大小有24个字节,24正好是整个结构体中最长长度8字节的整数倍,所以整个结构体a的大小就是24
typedef struct {
char a;
char b;
int c;
} AStruct;
typedef struct {
char d;
AStruct A;
char e;
} BStruct;
sizeof(AStruct) = 8;
sizeof(BStruct) = 16;

同上,d为char型,长度为1,因此在位置0,AStruct中最长的长度为4,按照规则三,所以AStruct的起始位置就是4,a在位置4,b在位置5,c按照规则一,在位置8~11,e则在位置12。此时总大小为13个字节,不满足规则二,即不是最宽长度4的整数倍,所以要补齐到16,也就如上图所示,BStruct总大小为16个字节,内存分布在0~15的位置上。
网友评论