C语言对 字节对齐 struct结构体大小 #parma pack()(一定能懂)
struct data_type1{
char a;
short b;
int c;
};
struct data_type2{
char a;
int c;
short b;
};
先看看上面两个结构体,如果有定义成对应的变量,它俩占内存空间是多少 ?如果你的答案是是相同,说明后面内容对你十分有用,一定会有收获的。
data_type1和data_type2结构体里的成员变量类型相同,两者的所占的空间应该是相同的,但是事实却不是如此。
经过实践编写代码输出的结果,却是这样的
为什么会出现这样的结果呢?
这是因为,编译器为数据进行了处理,做了字节对齐操作。又有疑惑?
什么是字节对齐?
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常是4或8)的倍数 ,这就是所谓的内存对齐。大白话就是,各种数据类型都要一定的规则进行排列,而不是一个接一个的排放,这就是对齐。
结构体的字节对齐规则?
1、对于结构的各个成员,第一个成员位于偏移为0的位置,以后的每个数据成员的偏移量必须是 min(#pragma pack()指定的数,这个数据成员的自身长度)的倍数。(默认#pragma pack(4 )).
2、在所有的数据成员完成各自对齐之后,结构或联合体本身也要进行对齐,对齐将按照 #pragram pack 指定的数值和结构或者联合体最大数据成员长度中比较小的那个。
说了那么多,我以前面的例子说明。
struct data_type1{
char a;
short b;
int c;
};
struct data_type2{
char a;
int c;
short b;
};
data_type1:char 占1个字节,偏移量是0;short占2个字节,min(4,sizeof(short)所以short的偏移量是2的整数倍,此时short的偏移量是1,要是2的整数倍,则需要在char后面补上一个字节,空数据;int占四个字节,min(4,sizeof(int)所以int的偏移量是4的整数倍,此时int 的偏移量2+2=4,刚好是4的整数倍;此时一共占了2+2+4=8个字节,但是还有结构体本身的对齐,min(4,结构体成员里最大数据类型int)=4;所以总体的字节数是4的整数倍,后面不需要添加字节。所以占用8个字节。
data_type2:char 占1个字节,偏移量是0;int占4个字节,min(4,intsizeof(int)所以int的偏移量是4的整数倍,此时int的偏移量是1,要是4的整数倍,则需要在char后面补上3个字节,空数据;short占2个字节,min(4,sizeof(short)所以short的偏移量是2的整数倍,此时short的偏移量4+4=8,刚好是4的整数倍,不需要添加字节;此时一共占了4+4+2=10个字节,但是还有结构体本身的对齐,min(4,结构体成员里最大数据类型int)=4;所以总体的字节数是4的整数倍,10不是4的整数倍,后面需要添加2个字节。所以占用12个字节。
怎么更改C编译器的缺省字节对齐方式?
使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
#pragma pack (1)//开始
struct data_type1{
char a;
short b;
int c;
};
struct data_type2{
char a;
int c;
short b;
};
#pragma pack ()//结束
两者的结构体都是以1字节进行对齐,不管顺序怎样,都占7个字节,但是有一点,与之前不修改字节对齐方式对比,cpu访问内存的效率降低。
为什么效率低,还要这样干?
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐。
为什么要字节对齐?
1、减少cpu访问变量的次数,cpu可以更快的读取数据
2、合理的使用字节对齐,可以节省内存的大小。
3、减少 cpu 访问数据的出错性(有些 cpu 必须内存对齐,否则指针访问会出错)。
|