内存对齐的原因:
1.平台原因
不是所有硬件平台都可以访问任意地址上的任意数据;
某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因
数据结构(尤其是栈)应该尽可能的在自然边界上对齐。
原因在于在访问未对齐的内存时,处理器需要进行两次内存访问;而对齐的内存访问仅需要一次。
结构体(struct)内存对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。
2.其它成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
//对齐数=编译器默认的一个对齐数与该成员大小的一个较小值
Vs中默认的对齐数是8
linux中默认的对齐数是4
3结构体总大小:最大对齐数(每个成员变量的除了第一个成员都有一个对对齐数)的整数倍。(每个成员变量在对 齐之后,把成员大小加起来,再扩大到最大对齐数的整数倍)
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有对齐数 (含嵌套结构体的对齐数)的整数倍。
联合体(union)的内存对齐规则:
1.联合体也是一个结构,联和体是共享内存的。
2.所以的联合体的内部成员起始地址都是一样的,都是联合体的首地址。
3.它的对齐方式要适应所有成员。
4.该空间必须足够容纳最宽成员。
5.联合体的对齐数为最大成员的对齐数。
位断(struct)的内存对齐规则:
1.如果相邻位域字段的类型相同,且其位宽之和小于sizeof(type)的大小,则后面的字段紧邻前一个字节存储,直到 容纳不下为止;基本成员是连续存储的,若这个单元空间放不下下一个成员,则新开辟一个单元空间,这样可以节 省内存空间。
2.如果相邻位域字段的类型相同,但其位宽之和大于sizeof(type)的大小,则后面的字段将从新的单元开始,偏移量 为其类型大小的整数倍。
3.如果相邻位域字段的类型不相同,则各编译器的实现有差异,vc6采取不压缩方式,Dev-c++采取压缩。
4.如果位域字段之间穿插着非位域字段,则不进行压缩。
5.结构体的总大小为最大对齐数的整数倍。因为位断成员必须声明为int、signed int或unsigned int类型,因此结构体的 大小都是4的整数倍。
下面我们看一个代码,通过以上规则计算其大小结构体,位断,联合体的大小:
在计算之前,我们首先需要明确的是各个数据成员的对齐模数,对齐模数和数据成员本身的长度以及PRagma pack()编译参数有关,#pragma pack(n) 可以设定对对齐数,编译器支持往比默认对齐数小的数调。对齐数=编译器默认的一个对齐数与该成员大小的一个较小值。如果程序没有明确指出,就需要知道编译器默认的对齐模数值。
下表是Windows xp/DEV-C++和Linux/GCC中基本数据类型的长度和默认对齐模数。
|
| char | short | int | long | float | double | long long | long double |
Win-32 | 长度 | 1 | 2 | 4 | 4 | 4 | 8 | 8 | 8 |
模数 | 1 | 2 | 4 | 4 | 4 | 8 | 8 | 8 | |
Linux-32 | 长度 | 1 | 2 | 4 | 4 | 4 | 8 | 8 | 12 |
模数 | 1 | 2 | 4 | 4 | 4 | 4 | 4 | 4 | |
Linux-64 | 长度 | 1 | 2 | 4 | 8 | 4 | 8 | 8 | 16 |
模数 | 1 | 2 | 4 | 8 | 4 | 8 | 8 | 16 |
#include<stdio.h>#include<windows.h>#pragma pack(4) //默认对齐数为4struct A{ char a1; //1+3 char占1个字节,double要对齐到4的整数倍处,所以1+3对其到4 double a2; //8 int a3; //4}; //结构体总大小:16 对齐数:4union un{ char b1; //1 struct A b2; //16 int b3; //4}; //联合体总大小:16 对齐数为:4(最大成员的对齐数)struct B{ unsigned int c1 : 4; //4 unsigned int c2 : 31; //位域 //4 unsigned int c3 ; //非位域 //4 unsigned int c4 : 1; //4}; //位断的总大小:16 对齐数:4 struct obj{ double d1; //8 char d2; //1+3 union un d3; //16 使1+3对齐到12,即4的整数倍 struct B d4; //16 char d5; //1+3 使1+3对齐到48,即4的整数倍 struct C{ struct B e1;//16 char e2; //1+3 使1+3对齐到20,即4的整数倍 double e3; //8 }; //总大小:28 对齐数:4 char d6; //1+3}; //结构体obj的总大小:80(使1+3对齐到80,即4的整数倍) 最大对齐数:4int main(){ printf("%d/n", sizeof(struct obj)); //结构体obj的总大小:80 system("pause"); return 0;}
新闻热点
疑难解答