内存对齐举例:
以下两个结构体:
#include<iostream>
using namespace std;
struct A{
char a;
int b;
short c;
};
struct B{
short c;
char a;
int b;
};
int main(){
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
return 0;
}
上面两个结构体A和B成员变量类型相同,但是占用的内存空间大小(单位:字节)却不一样
同样存储三个int(4)、char(1)、short(2)数据,不同定义方式,造成了结构体占用内存也不一样。这是因为内存对齐的需要。
内存对齐规则:
- 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
- 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
- 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
以上面结构体A为例,第一个成员a是char类型,占用1个字节空间,偏移量为0,第二个成员b是int类型,占用4个字节空间,按照规则1,b的偏移量必须是int类型的整数倍,所以编译器会在a变量后面插入3字节缓冲区,保证此时b的偏移量(4字节)是b类型的整数倍(当前恰好是1倍),第3个成员c为short类型,此时c的偏移量正好是4+4=8个字节,已经是short类型的整数倍,故b与c之间不用填充缓冲字节。但这时,结构体A的大小为8+2=10个字节,按照规则2,结构体A大小必须是其最大成员类型int的整数倍,所以在10个字节的基础上再填充2个字节,保证最后结构体大小为12,以符合规则2.
其实CPU是按字读取内存。所以内存对齐的话,不会出现某个类型的数据读一半的情况,需要再二次读取内存。可以提升访问效率。