今天突然用到了字节对齐的知识,所以看了几遍文章并做了些测试,总结如下
参考:
2.http://blog.youkuaiyun.com/kokodudu/article/details/11918219
3.http://www.cnblogs.com/repository/archive/2011/01/13/1933721.html
一.先看以下代码:
#include <iostream>
using namespace std;
struct A
{
int a;
char b;
short c;
};
struct B
{
char a;
int b;
short c;
};
#pragma pack(2)
struct C
{
char a;
int b;
short c;
};
#pragma pack(1)
struct D
{
int a;
char b;
short c;
};
int main()
{
cout << sizeof(A) << " "<< sizeof(B)<< " "<< sizeof(C)<< " "<< sizeof(D)<<endl;
return 0;
}
输出结果为
8 12 8 7
理论上来说,结构体A与B的大小应该都是一样的,造成这种原因的就是字节对齐引起来的
二.为什么要对齐呢?
简单点说:为了提高存取效率。字节是内存空间分配的最小单位, 在程序中,我们定义的变量可以放在任何位置。其实不同架构的CPU在访问特定类型变量时是有规律的,比如有的CPU访问int型变量时,会从偶数地址开始读取的,int类型占用4个字节(windows平台)。 0X0000,0X0004,0X0008.....这样只需要读一次就可以读出Int类型变量的值。相反地,则需要读取二次,再把高低字节相拼才能得到 int类型的值,这样子看的话,存取效率当然提高了。
三.编译器对字节对齐的一些规则
1.基本类型的自身对齐值:
类型对齐值
char 1
short 2
int 4
float 4
double 4(double自身长度虽然在x64上是8,但是它的对齐长度还是4)
2.类和结构体的对齐字节值:使用成员当中最大的对齐字节来对齐。比如在Struct A中,int a的对齐字节为4比char,short都大,所以A的对齐字节为4。
3.指定对齐值:使用了宏 #pragma pack(n)来指定的对齐值
4.类、结构及成员的有效对齐字节值:有效对齐值=min(类/结构体/成员的自身对齐字节值,指定对齐字节值)。有效对齐其实就是要求数据成员存放的地址值能被有效对齐值整除,即:地址值%有效对齐值=0,如果没有指定对齐字节值就使用编译器默认字节对齐值,这个值一般都大于4(为4或者8,64位g++多数网友说是8位),所以一般不会影响判断
规则虽然很多,但是我们实际使用中很少用到自己指定对齐值,所以后面3,4规则很少起作用,判断结构体占用字节或者sizeof返回值时主要根据1,2规则。
四.实例分析
从刚开始给的例子的A和B可以看出,内存对齐与结构体中变量声明的顺序有关
struct A
{
int a;
char b;
short c;
};
step 1: 根据第二条,首先为结构体选择对齐值:选择成员中最大的对齐值,即int a,对齐值为4
step 2: 再根据第四条原则,决定有效对齐值为4
step 3: int a 的有效地址值为4,这样a的地址就是从 0X0000~0x0003
step 4: char b 的有效对齐值为1,地址依次从0x0003 (因为Ox0003%1=0)开始,分配一个字节,char b地址段分配情况就是:0x0003~0x0004
step 5: short c 的有效对齐值为2,理论上说,分配的地址应该是连续的(从0x0005~0x00006),但是由于要求考虑到对齐的情况,所求要求地址段偏移,这样就从0x0006(Offset+1,因为0x0006%2=0)开始,分配2个字节的地址0x0006~0x0007.
目前为止,地址段的分配情况就是:0x0000~0x0007这样sizeof(A)的大小=0x0000~0x0007共8个字节大小,同时,8%4=0保证了Struct A的地址段与4成偶数倍。
struct B
{
char a;
int b;
short c;
};
step 1: 确实结构体B对齐值:选择成员中最大的对齐值,即int a,对齐值为4
step 2: char a 的有效地址值1,a的地址就是 0X0000(因为0x0000%1=0)
step 3: int b 的有效对齐值4,地址依次从0x0004~0x0007 (因为Ox0004%4=0)开始,分配4个字节,目前j地址段分配情况就是:0x0000~0x0007
step 5: short c 的有效对齐值2,c从0x0008~0x0009(因为0x0008%2=0)开始.
至止,地址段的分配情况就是:0x0000~0x0009共10个字节,但是Struct B的对齐值为4,这就要求地址地段再偏移2个字节,这样就是从0x0000~0x000B共12(因为12%4=0)个字节大小。这样,sizeof(B)=12