#pragma pack( n )和__declspec( align(#) ) 的偏移量计算方法

这么复杂的东西,不用中文压根说不清楚。用英文写,写了也等写火星文。

 

现在的一些处理器,需要你的数据的内存地址必须是对齐(align)的,即使不是必须,如果你对齐的话,运行的速度也会得到提升。虽然对齐会产生的额外内存空间,但相对于这个速度的提升来说,是值得的。

所谓对齐,就是地址必须能整除一个整数,这个就是对齐参数(alignment value)。合法的取值范围是124616、……、8192

怎样对齐呢?编译器帮你搞定。

怎样设置编译器的对齐方式呢?用#pragma pack( n )__declspec(align(#))

依据它俩,编译器是咋工作的?这个就是接下来要说的了。

 

#pragma pack( n )

不说别的,先直接举例说明这个n是这么用的。

#pragma pack( 4 )

struct A

{

             char a;

             short b;

             char c;

};

分配方法:

ü a是第一个,占[0]

ü short大小是22n=4小,用2对齐,即b的地址必须是2的倍数,所以[1]不用,b[2][3]

ü char大小是11n=4小,用1对齐,即c[4]

ü 算完各数据成员后,总共5B。最后,因为结构体A中最大的元素是2Bshort2n=4小,保证A的大小可以整除2,所以最后结果是6

ü 整个struct,内存分配情况是:a[0]b[2][3]c[4][1][5]不用。

 

MSDN的话一言以蔽之:

The alignment of a member (except the first one) will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.

翻译成中文,也就是:

结构体中的数据成员,除了第一个是始终放在最开始的地方,其它数据成员的地址必须是它本身大小或对齐参数两者中较小的一个的倍数。

 

按照这个理论,如果把上面的A的数据成员的顺序换一换的话,出现什么情况呢?

例如:

#pragma pack( 4 )

struct A

{

             char a;

             char c;

             short b;

};

分配方法:

ü a是第一个,占[0]

ü char大小是11n=4小,用1对齐,所以c[1]

ü short大小是22n=4小,用2对齐,即b[2][3]

ü 算完各数据成员后,总共4B。最后,因为结构体A中最大的元素是2Bshort2n=4小,保证A的大小可以整除2,所以最后结果是4

 

奇怪吧,改变数据成员的顺序是可以改变结构体的大小的。

 

特别提出:

ü A ao;
sizeof(ao.a )
还是1sizeof(ao.b )还是2

ü 如果struct B中含有A的一个对象m_a
struct B
{
  
   A m_a;
  
}
则这个m_a对齐参数是A中最大的数据类型的大小(这里是short2)和n中较小者。如果这个对齐参数是B中最大的话,最后B的大小也会与这个对齐参数有关。

 

__declspec( align(#) )

__declspec( align(#) )#pragma pack( n )有密切联系。

当一个变量或结构体同时受两者影响时,前者的优先级高。

成员的地址决定于前者及后者,其要么是前者的倍数,要么是后者的倍数,要么是成员的大小的倍数,取最小。

结构体最后的大小于前者有关,其要么是前者的倍数,要么是结构体中最大偏移量的倍数,取最大。

要算出最后结果,必须知道两者的值或缺省值。

 

惯例,直接给例子:

#pragma pack( push, 4 )

__declspec( align(32) )struct D

{

             Int i1;

             double d1;

             Int i2;

             Int i3;

};

ü I1是第一个,占[0][1][2][3]

ü double大小是88n=4大,用4对齐,所以d1[4][5][6][7][8][9][10][11]

ü int大小是22n=4小,用2对齐,即i2[12][13][14][15]

ü int大小是22n=4小,用2对齐,即i3[16][17][18][19]

ü 到现在为止,计算方法都和上面的几个例子完全一样。现在算出成员总共占了20B,而成员中最大的偏移量是4

ü 当计算结构体的最后大小时,因为结构体接受__declspec( align(32) )影响,比较4#4#=32小,用32补完,所以最后的大小应该是大于20B最小的32倍数,即32B

 

现在再定义含有DE

__declspec( align(16) ) struct E

{

             int i1;

             D m_d;

             int i2;

};

 

#pragma pack( pop )

ü I1是第一个,占[0][1][2][3]

ü m_d受之前的__declspec( align(32) )影响,优先级高,偏移量是32,用32对齐,所以d1[32]-[63]

ü int大小是22n=4小,用2对齐,即i2[64][65][66][67]

ü 现在算出成员总共占了68B,而成员中最大的偏移量是32

ü 当计算结构体的最后大小时,因为结构体接受__declspec( align(16) )影响,比较32#32#=16大,用32补完,所以最后的大小应该是大于68B最小的32倍数,即96B

 

MSDN:

The sizeof value for any structure is the offset of the final member, plus that member's size, rounded up to the nearest multiple of the largest member alignment value or the whole structure alignment value, whichever is greater.

中文:

sizeof的结果都是结构体中最后的一个成员变量加上它的大小,再加上一个填充容量(padding),这个填充大小是成员变量最大的一个对齐参数或整个结构体的对齐参数的倍数,取哪个决定于哪个对齐参数较大

 

参考:

MSDN

ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/dv_vclang/html/e4209cbb-5437-4b53-b3fe-ac264501d404.htm

ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/dv_vclang/html/9cb63f58-658b-4425-ac47-af8eabfc5878.htm

 

网站:

http://blog.sina.com.cn/s/blog_492aa57901008y3h.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值