结构体对齐方式

对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。

语法:#pragma pack( [show] | [push | pop] [, identifier], n )

对齐的算法: 由于各个平台和编译器的不同,可能会有所不同,本文是在window 2008 32位系统 vs2005上尝试的。

在不指定对齐方式时 编译器默认大小为8

可以通过命令 #pragma pack (show) 查看

那就从默认的开始说起,由于默认是8 ,结构体如下

typedef struct TEST_S
{
     char b;

     int a;

    short c;

};

sizeof(TEST_S) = ?   应该是12,为何?

原因:

假设TEST_S从地址空间0x0000开始存放。没有定义指定对齐值,该值默认为8。
第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值8小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.
第二个成员变量a,其自身对齐值为4,比指定或者默认指定对齐值8小,所以其有效对齐值为4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,符合0x0004%4=0, 且紧靠第一个变量。
第三个变量c,自身对齐值为2,比指定或者默认指定对齐值8小,所以其有效对齐值为2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存放的都是B内容。
再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(struct B)=12;

==================分割线================================

 重新指定对齐大小

#pragma pack(push)
#pragma pack(2)

typedef struct TEST_S
{
     char b;

     int a;

    short c;

};

#pragma pack(pop)

 sizeof(TEST_S) = ?   应该是8,为何?

原因:

假设TEST_S从地址空间0x0000开始存放。指定对齐值为2。
第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值2小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.
第二个成员变量a,其自身对齐值为4,比指定或者默认指定对齐值2大,所以其有效对齐值为2,所以只能存放在起始地址为0x0002到0x0005这四个连续的字节空间中,符合0x0002%2=0, 且紧靠第一个变量。
第三个变量c,自身对齐值为2,与指定或者默认指定对齐值2一样,所以其有效对齐值为2,可以存放在0x0006到0x0008这两个字节空间中,符合0x0006%2=0。所以从0x0000到0x0008存放的都是B内容。
再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,但结构体的有效对齐值是2。根据结构体圆整的要求,0x0008到0x0000=8字节,(8)%2=0。所以B从0x0000到0x0008共有8个字节,sizeof(struct B)=8;

==================分割线================================

重新指定对齐大小

#pragma pack(push)
#pragma pack(1)

typedef struct TEST_S
{
     char b;

     int a;

    short c;

};

#pragma pack(pop)

 sizeof(TEST_S) = ?   应该是7,为何?

原因:

假设TEST_S从地址空间0x0000开始存放。指定对齐值为1。
第一个成员变量b的自身对齐值是1,与指定或者默认指定对齐值1一样,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.
第二个成员变量a,其自身对齐值为4,比指定或者默认指定对齐值1大,所以其有效对齐值为1,所以只能存放在起始地址为0x0001到0x0004这四个连续的字节空间中,符合0x0001%1=0, 且紧靠第一个变量。
第三个变量c,自身对齐值为2,比指定或者默认指定对齐值1大,所以其有效对齐值为1,可以存放在0x0005到0x0007这两个字节空间中,符合0x0005%1=0。所以从0x0000到0x0007存放的都是B内容。
再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,但结构体的有效对齐值是1。根据结构体圆整的要求,0x0007到0x0000=7字节,(7)%1=0。所以B从0x0000到0x0007共有7个字节,sizeof(struct B)=7;

=======================分割线==================

现在思路是否清晰一些呢,现在如果在增加一个结构体成员 在看看什么效果

#pragma pack(push)
#pragma pack(2)

typedef struct TEST_S
{
     char b;

  char e;

     int a;

    short c;

};

#pragma pack(pop)

 sizeof(TEST_S) = ?   应该是8,为何?

增加了一个成员 在长度没变。如果指定对齐大小为4呢 ?sizeof(TEST_S) = ?   应该是12

根据上面的理论应该都可以推算出来的~

总结一下:

1:如果没指定对齐大小 ,那就按照默认大小对齐,默认值大小为多少可以通过命令查看,前面已经提到了。

2:如果指定了对齐大小,那就要看结构体里的成员大小与指定大小比较,按照值较小的对齐。

3:计算大小的同时 要注意结构体的取整要求。

原文地址:https://www.cnblogs.com/seer/p/3582932.html