内存对齐概念:
要了解内存对齐,我们可以先看下面的例子:
typedef struct S {
int a;
double b;
char c;
}S;
typedef struct B {
int a;
char b;
double c;
}B;
int main() {
printf("S : %d\n", sizeof(S));
printf("B : %d\n", sizeof(B));
return 0;
}
上面的输出结果为:
S : 24
B : 16
可见sizeof(S)和sizeof(B)是不同的,为什么会不同呢?原因在于结构体在分配时有其具体的对齐规则。
简单来说就是按照成员的定义顺序,依次为其分配内存,分配内存的起始偏移位置应该是选定对齐数的整数倍,最后结构体变量所占大小应该是成员最大对齐数的整数倍。
内存对齐计算:
要学会计算内存对齐,首先要了解内存对齐的规则:
1.在任何一个平台下都有一个默认对齐数,vs中默认对齐数是8
2.结构体每个成员变量又有一个自己独立的对齐数,就是成员变量类型的大小
3.实际成员变量的对齐数是成员自己独立的对齐数与默认对齐数中较小的那个
4.每个成员变量都应该对齐到这个对齐数的整数倍处
5.结构体的总大小,应该是实际最大对齐数的整数倍大小,不足则补位
6.如果成员变量也是结构体变量,则这个结构体变量的对齐数,为自己结构内部的实际最大对齐数
typedef struct S {
int a;
double b;
char c;
}S;
计算过程为:
对结构体S来说:
a变量占四个字节,b变量的对齐数为8,所以b应该从偏移量为8处开始储存(4~7均不是对齐数的整数倍),c变量的对齐数为1,所以c应该从偏移量为17处开始储存,所以得到的应该是17,根据规则 5.结构体的总大小,应该是实际最大对齐数的整数倍大小,不足则补位 而17不是8的整数倍,所以补位成8的整数倍,所以sizeof(S)输出24.
typedef struct B {
int a;
char b;
double c;
}B;
计算过程为:
对结构体B来说:
a变量占四个字节,b变量的对齐数为1,所以b应该从偏移量为4处开始储存,c变量的对齐数为8,所以c应该从偏移量为8处开始储存,所以得到的应该是16,根据规则 5.结构体的总大小,应该是实际最大对齐数的整数倍大小,不足则补位 16是8的整数倍,所以sizeof(B)直接输出16.
为什么要内存对齐:
内存对齐的好处:
1. 不是所有的硬件平台都支持随意地址访问,有些硬件平台cpu只能从指定地址处读取指定大小的数据,减少了异常抛出。
2. 提高结构体成员的访问效率,访问未对齐的内存时可能需要进行两次访问操作,内存对齐之后只需要进行一次访问。