内存对齐?什么是内存对齐?
对于这个问题我们先来看看这样的一个结构体(在32位系统下)
typedef struct Stu1
{
char C1;
int num1;
short S1;
}Stu1;
如果我们不知道内存对齐或者不清楚内存对齐时,我们可能这样分析:
C1占一个字节,num1占4个字节,S1占2个字节,所以该结构体占7个字节。
然后我再VS2017上测试发现得到12个字节。
这是为什么呢?这就是由于内存对齐导致的。
为什么会是这样?在解决这个问题时,先来了解一下内存对齐规则:
1.结构体的第一个成员在结构体变量偏移量为0的地址处。就是结构体地址和第一个元素的地址的值是一样的,够明了吧。
2.剩下的成员变量要对齐到对齐数的整数倍的地址上。
对齐数听起来很高大上的样子,其实一点也不牛逼,就是一个数罢了,就是该结构体的成员占几个字节就是对齐数,每个成员变量都对应一个对齐数。
最大对齐数就是:编译器的设定对齐数字和结构体中成员占字节最大的那个相比取最小的。怎么样?它就那么回事。
3.结构体的总体大小就是对齐数的整数倍。
4.再嵌套结构体的话,别担心会复杂,你可以这样做就是把嵌套的结构体中变量最大的对齐数和这个结构体相比对齐到最大对齐数上。结构体的整体大小就是所有最大对齐数的整数倍。
现在来看上面的问题:第一个C1开始是对齐数是1就是“1”,但遇到num时就变成了4,所以是“1*** 1111”,再遇到S1发现它对齐数小于num1所以还是4,所以是这样存储:“1*** 1111 11**”。
那么可不可以既提高效率,又能节省空间,有一个小技巧可以解决这样的问题。
再来看一个例子:
typedef struct Stu2
{
char C1;
short S1;
int num1;
}Stu2;
和上面的看起来没什么区别,但是注意顺序变了,我们再走一遍看看它是如何进行内存对齐的?
C1开始对齐数是一那就占一个字节,“1”,接着S1占2个字节那就是“1* 11”,接着num1占4个字节那就是:“1*11 1111”。
不过瘾?那再来来几个小试牛刀:
#include<stdio.h>
#include<stdlib.h>
typedef struct student1
{
char name[1020];
double score;
int num;
long long ShenFenZheng;
}student1;
typedef struct student2
{
char name[1020];
int num;
double score;
long long ShenFenZheng;
}student2;
typedef struct student3
{
char name[1024];
double score;
int num;
long long ShenFenZheng;
}student3;
typedef struct Stu1
{
// student4 stu;
char C1;
int num1;
short S1;
}Stu1;
typedef struct Stu2
{
char C1;
short S1;
int num1;
}Stu2;
typedef struct student4
{
Stu1 S1;
char name[1024];
int num;
double score;
long long ShenFenZheng;
}student4;
void Mysizeof()
{
printf("%d\n", sizeof(Stu1));//12
printf("%d\n", sizeof(Stu2));//8
printf("%d\n", sizeof(student3));//1048
printf("%d\n", sizeof(student4));//1056
printf("%d\n", sizeof(student1));//1048
printf("%d\n", sizeof(student2));//1040
}
int main()
{
Mysizeof();
system("pause");
return 0;
}
(二)为什么要内存对齐?
1.移植原因:由于所有的硬件平台并不是都能访问任意地址上的任意数据的,有的硬件平台只能在某些地址处取某些特定类型数据,否则抛出异常。
2.性能原因:上面已经提及,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于是为了访问未对齐的内存,处理器需要做内存访问;而对齐的内存访问进需要一次访问。
结构体的内存对齐就是用空间换时间的做为。(鱼和熊掌不可兼得,哈哈^_^。。。)
补充说明:
1. 每个结构体变量成员在对齐时先按自己的对齐方式对齐,并可以最小化长度。
2. 对齐后的长度必须是该结构体的最大对齐数的整数倍。
3. 字符数组char array[1024],它是以char占的字节进行对齐,而不是数组的长度。
4. 我们也可以修改编译器的默认对齐数。
两种方式:
1. #pragma pack(n) //n可以设定为需要对齐的数。但注意只能是2的指数倍。
对应的如何取消设定值呢?,在结构体后面加上:#pragma pack() 就可以了,还原为默认值。
2. 另外可以在编译器我以VS为例:在工程的属性页 ---> C/C++ ---> 代码生成 ---> 结构成员对齐,可以修改默认值。
珍&源码