为什么要内存对齐
对于CPU从内存读取数据,并不是我们想象的那样,直接前去读取对应的大小,为了提升效率和速度,CPU会按照内存读取粒度的大小来读取内从中的数据,比如说如果内存读取粒度是4个字节,那么CPU会一次读取4个字节的内存,就算读取char类型的数据,虽然它只占1个字节,但是CPU依然会读取4个字节,然后从四个字节中取出char类型的数据,因此就产生了内存对齐这样的问题,也就是在结构体这样的类型中,他所占的大小并不一定是组成它的成员的大小之和,他还需要考虑内存对齐的问题。内存对齐主要是为了提高读取速度。
其中如果 不内存对齐 部分 CPU还不支持不内存对齐,也就是说可能会产生直接崩溃的现象。
因此内存对齐 也是为了平台移植的原因。
还有内存对齐可以提高访问内存的速度
内存对齐的规则
分为2步:
1. 结构体中的类型 第一个类型偏移量是0 其他类型要根据规则来计算偏移量 偏移量为 min(#pragma pack(),该类型所占字节大小) 的倍数
2. 结构体最终的总大小是 min(#pragma pack(),结构体中最大类型的字节大小) 的倍数
内存对齐例子
struct structA{
char c;
int a;
short s;
}
struct structB{
short s;
char c;
int a;
}
对于这两个结构体 structA和structB 在内存中占的大小 却不是一样的
sizeof(structA) : 12字节
sizeof(structB) : 8字节
这是为什么呢? 结构体中内容一样,当时在内存中所占的大小却是不一样的
下面我们就按照上述的内存对齐规则来计算一下他俩在内存中所占的大小:
structA:
struct structA{
char c;
int a;
short s;
}
首先 它的第一个成员 char c; 大小为 1个字节 由于是第一个元素 所以它的偏移量为0 处于 0位置
第二个成员 int a; 大小为 4个字节 #pragma pack() 的大小是 8字节 min(#pragma pack(),变量大小) = 4字节 因此偏移量为4的倍数 为4
处于4 5 6 7地址位置 1 2 3 位置空闲
第三个成员 short s; 大小为 2个字节 #pragma pack() 的大小是 8字节 min(#pragma pack(),变量大小) = 2字节 因此偏移量为2的倍数 为
8 处于 8 9位置
这样就完成了第一步的对齐
之后进行第二步对齐,由于结构体中最大的成员是int 占4个字节 #pragma pack()等于8 因此 结构体总的大小应该为 4的倍数 所以应该为12字节
这样就计算出了内存中占有的实际内存大小
structB:
struct structB{
short s;
char c;
int a;
}
pragma pack() = 8
首先它的第一个成员为short类型 偏移量为0 占有 0 1位置
第二个成员为char类型 大小为1 因此偏移量为 1的倍数 为 2 占 2 这个位置
第三个成员为int 类型 大小为4字节 因此偏移量为 4的倍数 也就是 4
占 4 5 6 7 位置 3 位置空闲
因此 第一步对齐后 占有 0 -7的地址位置 大小为8字节
而结构体中最大的为int 4个字节 而8是 4的倍数 因此 此结构体在内存中占有的大小就是 8个字节
这样就解释清楚了内存对齐的规则,希望我以后不会忘记。。。。