#pragma pack( n )和__declspec( align(#) ) 的偏移量计算方法
2009-07-27 15:19
351 查看
http://blog.csdn.net/DONALDO_O/archive/2008/11/15/3306588.aspx
这么复杂的东西,不用中文压根说不清楚。用英文写,写了也等写火星文。
现在的一些处理器,需要你的数据的内存地址必须是对齐(
align
)的,即使不是必须,如果你对齐的话,运行的速度也会得到提升。虽然对齐会产生的额外内存空间,但相对于这个速度的提升来说,是值得的。
所谓对齐,就是地址必须能整除一个整数,这个就是对齐参数(
alignment value
)。合法的取值范围是
1
、
2
、
4
、
6
、
16
、……、
8192
。
怎样对齐呢?编译器帮你搞定。
怎样设置编译器的对齐方式呢?用
#pragma pack( n )
和
__declspec(align(#
))
。
依据它俩,编译器是咋工作的?这个就是接下来要说的了。
#pragma pack( n )
不说别的,先直接举例说明这个
n
是这么用的。
#pragma pack( 4 )
struct A
{
char a;
short b;
char c;
};
分配方法:
ü
a
是第一个,占
[0]
ü
short
大小是
2
,
2
比
n=4
小,用
2
对齐,即
b
的地址必须是
2
的倍数,所以
[1]
不用,
b
占
[2]
、
[3]
ü
char
大小是
1
,
1
比
n=4
小,用
1
对齐,即
c
占
[4]
ü
算完各数据成员后,总共
5B
。最后,因为结构体
A
中最大的元素是
2B
的
short
,
2
比
n=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
大小是
1
,
1
比
n=4
小,用
1
对齐,所以
c
占
[1]
ü
short
大小是
2
,
2
比
n=4
小,用
2
对齐,即
b
占
[2][3]
ü
算完各数据成员后,总共
4B
。最后,因为结构体
A
中最大的元素是
2B
的
short
,
2
比
n=4
小,保证
A
的大小可以整除
2
,所以最后结果是
4
。
奇怪吧,改变数据成员的顺序是可以改变结构体的大小的。
特别提出:
ü
A ao;
sizeof(ao.a )
还是
1
,
sizeof(ao.b )
还是
2
。
ü
如果
struct B
中含有
A
的一个对象
m_a
,
struct B
{
…
A m_a;
…
}
则这个
m_a
对齐参数是
A
中最大的数据类型的大小(这里是
short
的
2
)和
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
大小是
8
,
8
比
n=4
大,用
4
对齐,所以
d1
占
[4][5][6][7][8][9][10][11]
。
ü
int
大小是
2
,
2
比
n=4
小,用
2
对齐,即
i2
占
[12][13][14][15]
ü
int
大小是
2
,
2
比
n=4
小,用
2
对齐,即
i3
占
[16][17][18][19]
ü
到现在为止,计算方法都和上面的几个例子完全一样。现在算出成员总共占了
20B
,而成员中最大的偏移量是
4
。
ü
当计算结构体的最后大小时,因为结构体接受
__declspec( align(32) )
影响,比较
4
和
#
,
4
比
#=32
小,用
32
补完,所以最后的大小应该是大于
20B
最小的
32
倍数,即
32B
。
现在再定义含有
D
的
E
__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
大小是
2
,
2
比
n=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
),这个填充大小是成员变量最大的一个对齐参数或整个结构体的对齐参数的倍数,取哪个决定于哪个对齐参数较大
”
这么复杂的东西,不用中文压根说不清楚。用英文写,写了也等写火星文。
现在的一些处理器,需要你的数据的内存地址必须是对齐(
align
)的,即使不是必须,如果你对齐的话,运行的速度也会得到提升。虽然对齐会产生的额外内存空间,但相对于这个速度的提升来说,是值得的。
所谓对齐,就是地址必须能整除一个整数,这个就是对齐参数(
alignment value
)。合法的取值范围是
1
、
2
、
4
、
6
、
16
、……、
8192
。
怎样对齐呢?编译器帮你搞定。
怎样设置编译器的对齐方式呢?用
#pragma pack( n )
和
__declspec(align(#
))
。
依据它俩,编译器是咋工作的?这个就是接下来要说的了。
#pragma pack( n )
不说别的,先直接举例说明这个n
是这么用的。
#pragma pack( 4 )
struct A
{
char a;
short b;
char c;
};
分配方法:
ü
a
是第一个,占
[0]
ü
short
大小是
2
,
2
比
n=4
小,用
2
对齐,即
b
的地址必须是
2
的倍数,所以
[1]
不用,
b
占
[2]
、
[3]
ü
char
大小是
1
,
1
比
n=4
小,用
1
对齐,即
c
占
[4]
ü
算完各数据成员后,总共
5B
。最后,因为结构体
A
中最大的元素是
2B
的
short
,
2
比
n=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
大小是
1
,
1
比
n=4
小,用
1
对齐,所以
c
占
[1]
ü
short
大小是
2
,
2
比
n=4
小,用
2
对齐,即
b
占
[2][3]
ü
算完各数据成员后,总共
4B
。最后,因为结构体
A
中最大的元素是
2B
的
short
,
2
比
n=4
小,保证
A
的大小可以整除
2
,所以最后结果是
4
。
奇怪吧,改变数据成员的顺序是可以改变结构体的大小的。
特别提出:
ü
A ao;
sizeof(ao.a )
还是
1
,
sizeof(ao.b )
还是
2
。
ü
如果
struct B
中含有
A
的一个对象
m_a
,
struct B
{
…
A m_a;
…
}
则这个
m_a
对齐参数是
A
中最大的数据类型的大小(这里是
short
的
2
)和
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
大小是
8
,
8
比
n=4
大,用
4
对齐,所以
d1
占
[4][5][6][7][8][9][10][11]
。
ü
int
大小是
2
,
2
比
n=4
小,用
2
对齐,即
i2
占
[12][13][14][15]
ü
int
大小是
2
,
2
比
n=4
小,用
2
对齐,即
i3
占
[16][17][18][19]
ü
到现在为止,计算方法都和上面的几个例子完全一样。现在算出成员总共占了
20B
,而成员中最大的偏移量是
4
。
ü
当计算结构体的最后大小时,因为结构体接受
__declspec( align(32) )
影响,比较
4
和
#
,
4
比
#=32
小,用
32
补完,所以最后的大小应该是大于
20B
最小的
32
倍数,即
32B
。
现在再定义含有
D
的
E
__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
大小是
2
,
2
比
n=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
),这个填充大小是成员变量最大的一个对齐参数或整个结构体的对齐参数的倍数,取哪个决定于哪个对齐参数较大
”
相关文章推荐
- #pragma pack( n )和__declspec( align(#) ) 的偏移量计算方法
- #pragma pack( n )和__declspec( align(#) )
- (转)内存对齐 #pragma pack(n) __declspec(align(#))
- (经典)struct和 union用 sizeof 看字节对齐,以及__declspec( align( # ) ) 和 #pragma pack()的使用方式
- 关于内存对齐#pragma pack( n )和__declspec( align(#) 的理解
- #pragma pack()与__declspec(align())
- struct和 union用 sizeof 看字节对齐,以及__declspec( align( # ) ) 和 #pragma pack()的使用方式
- 内存对齐 (一) #pragma pack的用法及大小的计算
- Webpack打包css后z-index被重新计算的解决方法,webpackz-index
- 【转载】【内存对齐(二)】__declspec( align(#) )的用法和大小计算
- 查表指令中计算偏移量的简便方法
- 【转载】【内存对齐(二)】__declspec( align(#) )的用法和大小计算
- 【内存对齐(一)】#pragma pack的用法及大小的计算
- pragma pack & align()
- (转载) 内存对齐 (一) #pragma pack的用法及大小的计算
- Webpack打包css后z-index被重新计算的解决方法
- 【内存对齐(一)】#pragma pack的用法及大小的计算(转)
- C语言计算一个结构体内成员地址的偏移量的两种方法(代码实例)
- 计算结构体中偏移量的方法
- C语言字节对齐 __align(),__attribute((aligned (n))),#pragma pack(n)