简单理解结构体的内存对齐
程序员文章站
2022-03-15 22:23:24
...
学习总结
首先了解内存对齐是什么?
简单来讲内存对齐是一种提高内存访问速度的策略,cpu在访问未对其的内存需要经过俩次内存访问,而经过内存对齐一次就可以了。
首先我们要引入一个概念:内存的自然对齐:每一种数据类型都必须放在地址中的整数倍上。
举个例子如下:
#include <iostream>
using namespace std;
struct Examples
{
char a;
int b;
long long c;
short d;
char f;
};
int main()
{
Examples ls;
cout << sizeof(Examples) <<endl;
printf("00%X\n", &(ls.a));
cout << &(ls.b) << endl;
cout << &(ls.c) << endl;
cout << &(ls.d) << endl;
printf("00%X\n", &(ls.f));
return 0;
}
/*
此时 Examples结构体的大小为24字节
ls.a的起始地址是 00B9FAD8
ls.b的起始地址是 00B9FADC
ls.c的起始地址是 00B9FAE0
ls.d的起始地址是 00B9FAE8
ls.f的起始地址是 00B9FAEA
*/
由上面例子我们可以进行一个内存对齐的判断
首先 把 char a 的内存地址定为起始地址,我们就可以计算出 a 与 b 相差了4个字节大小的内存地址。所以我们可以判断出 char a与 int b 进行了一次内存对齐, char a的内存大小被对齐为了4个字节。
然后我们 再来计算 b、c、d、f之间的内存地址之差,b与c之间的内存差为4个字节 而c与d之间的内存差为8个字节,d与f之间的内存差为8个字节。 这里我们可以看出 int b的在结构体中的内存大小为 4个字节,long long c 在结构体中的内存大小为8个字节,short d 的内存大小被对齐为 8个字节,d与f之间的内存差为 2个字节。
由上面的计算 我们可以得出
char a 的内存大小为4个字节
int b 的内存大小为4个字节
long long c 的内存大小为8字节
short d 的内存大小为8字节
看到此次大家就会有疑问, char f 去哪了呢?
其实 char f 被通过自然对齐 对齐到了 short d 的内存空间中, 我们可以从d与f 的内存差看出 f是在 d的8字节内存当中。
依旧可以使用一个示例来展示:
#include <iostream>
using namespace std;
struct Examples
{
char a;
short g;
int b;
long long c;
short d;
char f;
};
int main()
{
Examples ls;
cout << sizeof(Examples) <<endl;
printf("00%X\n", &(ls.a));
cout << &(ls.g) << endl;
cout << &(ls.b) << endl;
cout << &(ls.c) << endl;
cout << &(ls.d) << endl;
printf("00%X\n", &(ls.f));
return 0;
}
/*
此时 Examples结构体的大小依旧为24字节
ls.a的起始地址是 00CFF904
ls.g的起始地址是 00CFF906
ls.b的起始地址是 00CFF908
ls.c的起始地址是 00CFF90C
ls.d的起始地址是 00CFF914
ls.f的起始地址是 00CFF916
*/
内存对齐三原则:
- 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
- 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
- 结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐。