结构体在内存中的存储(内存对齐)
Posted 两片空白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构体在内存中的存储(内存对齐)相关的知识,希望对你有一定的参考价值。
一.内存对齐是什么
首先看例子:
#include<stdio.h>
struct stu{
char a;
int b;
char c;
};
int main(){
printf("%d\\n", sizeof(struct stu ));
return 0;
}
输出:
按照正常的思维,上述结构体中,两个char类型占一字节,一个int类型占四字节,一共应该是6字节,那为什么输出是12字节呢。
再看一个代码。
#include<stdio.h>
struct stu{
char a;
char c;
int b;
};
int main(){
printf("%d\\n", sizeof(struct stu ));
return 0;
}
输出:
上面代码与第一个代码相同,只是结构体中将char类型与int类型交换了一下位置,输出就变成了8字节。
通过上面两个代码发现,结构体在内存中的不是简单的按字节累加的,是存在一定规律储存再内存中的。这个规律就是内存对齐。
我们知道,数据都是保存在内存中的,而计算是在CPU内进行的,在计算是CPU要将数据从内存拿到CPU里,但是,CPU在访存时,不是直接从地址中那数据的,CPU必须遵守某些硬件规则进行访存。
下面举个例子:
如上如果结构体是这样存储的,要取出数据是很繁琐的。
如果像上面这样存储,CPU只要直接访存地址就好了,效率就会提高很多。这样存储的方式就是内存对齐。
但是CPU访存的规则是按着计算硬件来的,是不一样的。上面只是举个例子。
总结:通过牺牲空间,换取效率提升保存数据的方案叫做内存对齐。
那为什么要内存对齐呢?如果不内存对齐,因为硬件平台限制,导致访存次数增加,进而会降低效率。
二.怎样内存对齐
首先要掌握结构体对齐的规则:
-
第一个成员在与结构体变量偏移量为0的地址处。
偏移量:结构体成员前面的字节数。 第一个结构体成员前偏移量为0 所以在保存时不需要对齐。
-
其它成员变量要对齐到对齐数的整数倍地址处。
对齐:怎么对齐呢?偏移量能够整数对齐数。不能整除补字节数直到能整除。 对齐数:对齐数=编译器默认对齐数与该成员大小的较小值。一般编译器没有对齐数,对齐数一般就是成员大小。
-
结构体总大小为最大对齐数(每一个成员包括第一个成员)的整数倍。
最大对齐数为所有成员中对齐数的最大值。 结构体大小计算完后还需要看是否能整除最大对齐数,不能整除补字节数。
-
如果嵌套结构体的情况,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是最大对齐数(含嵌套结构体的对齐数)的整数倍。
先算出嵌套的结构体的最大对齐数,为外层结构体的对齐数,嵌套结构体的总大小为放在外层结构体的大小。
#include<stdio.h>
struct s1{
double a;//偏移量为 0 对齐数为8 放8个字节
char b;//偏移量为8 对齐数为1 可以整除 放1个字节
int c;//偏移量为9 对齐数为4 不能整除 补3个字节 放4个字节
};
//s1 最大对齐数为8 一共8+1+3+4=16可以整除8 于是结构体大小为8
struct s2{
char d; //偏移量为 0 对齐数为1 放1个字节
struct s1 s;//偏移量为1 对齐数为s1的最大对齐数8 不能整除 补7个字节 放结构体大小的字节16个
int e;//偏移量为24 对齐数为4 可以整除 放4个字节
};
//s2 最大对齐数为8 一共1+7+16+4=28 不能整除8 补4字节 一共为32字节。
int main(){
printf("%d\\n", sizeof(struct s1 ));
printf("%d\\n", sizeof(struct s2));
return 0;
}
输出:
注意当嵌套数组时:由于数组里面元素类型相同,只需要第一个元素对齐就好了。
#include<stdio.h>
struct stu{
char a;
int c[5];//对齐数4 大小20
char b;
};
int main(){
printf("%d\\n", sizeof(struct stu ));
return 0;
}
输出:
三.修改默认对齐数
用#pragma pack()指令可以修改默认对齐数。
#include<stdio.h>
#pragma pack(2)//设置默认对齐数为2
//对齐数为成员大小与系统默认对齐数的较小值。对齐数为2
struct s1{
double a;//偏移量为 0 对齐数为2 放8个字节
char b;//偏移量为8 对齐数为1 可以整除 放1个字节
int c;//偏移量为9 对齐数为2 不能整除 补1个字节 放4个字节
};
//一共8+1+1+4=14 最大对齐数为2 可以整数 于是结构体大小为14
int main(){
printf("%d\\n", sizeof(struct s1));
return 0;
}
#pragma pack()里面不加数字为:取消设置的默认对齐数。
以上是关于结构体在内存中的存储(内存对齐)的主要内容,如果未能解决你的问题,请参考以下文章