对结构MyStruct采用sizeof会出现什么结果呢?sizeof(MyStruct)为多少呢?
也许你会这样求:
sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13
但是当在
VC
中测试上面结构的大小时,你会发现
sizeof(MyStruct)
为
16
。你知道为什么在
VC
中会得出这样一个结果吗?
其实,这是
VC
对变量存储的一个特殊处理。为了提高
CPU
的存储速度,
VC
对一些变量的起始地址做了
“
对齐
”
处理
。在默认情况下,
VC
规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式
(vs6.0 &vs8.0,32
位系统
)
。
类型
|
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
|
char
|
偏移量必须为
sizeof(char)
即
1
的倍数
|
short
|
偏移量必须为
sizeof(short)
即
2
的倍数
|
int
|
偏移量必须为
sizeof(int)
即
4
的倍数
|
float
|
偏移量必须为
sizeof(float)
即
4
的倍数
|
double
|
偏移量必须为
sizeof(double)
即
8
的倍数
|
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节
VC
会自动填充。同时
VC
为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
下面用前面的例子来说明
VC
到底怎么样来存放结构的。
struct MyStruct { double dda1; char dda; int type; };
为上面的结构分配空间的时候, VC 根据成员变量出现的顺序和对齐方式,依次分配。
struct MyStruct { double dda1; char dda; int type; };
为上面的结构分配空间的时候, VC 根据成员变量出现的顺序和对齐方式,依次分配。
(
1
)先为第一个成员
dda1
分配空间,其起始地址跟结构的起始地址相同,刚好偏移量
0
刚好为
sizeof
(double)
的倍数,该成员变量占用
sizeof
(double)
=8
个字节;
(
2
)接下来为第二个成员
dda
分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量
为
8
,是
sizeof
(char)
的倍数,所以把
dda
存放在偏移量为
8
的地方满足对齐方式,该成员变量占
用
sizeof
(char)
=1
个字节;
(
3
)
接下来为第三个成员
type
分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移
量为
9
,不是
sizeof
(int)
=4
的倍数,为了满足对齐方式对偏移量的约束问题,
VC
自动填充
3
个字
节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为
12
,
刚好是
=4
的倍数,所以把
type
存放在偏移量为
12
的地方,该成员变量占用
sizeof
(int)
=4
个字节;
(
4
)
这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:
8+1+3+4=16
,刚好为
结构的字节边界数(即结构中占用最大空间的类型所占用的字节数
sizeof
(double)
=8
)的倍数,所
以没有空缺的字节需要填充。
(
5
)
所以整个结构的大小为:
sizeof(MyStruct)=8+1+3+4=16
,其中有
3
个字节是
VC
自动填充的,没
有放任何有意义的东西。
下面再举个例子,交换一下上面的
MyStruct
的成员变量的位置,使它变成下面的情况:
struct MyStruct {
char
dda;
double dda1; int type; };
这个结构占用的空间为多大呢?在
VC6.0
环境下,可以得到
sizeof(MyStruc)
为
24
。结合上面提到的分配空间的一些原则,分析下
VC
怎么样为上面的结构分配空间的。(简单说明)
struct MyStruct { char dda;
struct MyStruct { char dda;
/*
偏移量为0,满足对齐方式,dda占用1个字节;*/
double
dda1;
/*
下一个可用的地址的偏移量为1,不是sizeof(double)=8的倍数,需要补足个字节才能使偏移量变为(满足对齐方式),因此VC自动填充7个字节,dda1存放在偏移量为8的地址上,它占用8个字节。*/
int
type
;
/*
下一个可用的地址的偏移量为16,是sizeof(int)=4的倍数,满足int的对齐方式,所以不需要VC自动填充,type存放在偏移量为的地址上,它占用4个字节。*/
};
所有成员变量都分配了空间,空间总的大小为
1+7+8+4=20
,不是结构的节边界数(即结构中占用最大空间的类型所占用的字节数
sizeof(double)=8
)的倍数,所以需要填充
4
个字节,以满足结构的大小为
sizeof(double)=8
的倍数。
所以该结构总的大小为: sizeof(MyStruc) 为 1+7+8+4+4=24 。其中总的有 7+4=11 个字节是 VC 自动填充的,没有放任何有意义的东西。
所以该结构总的大小为: sizeof(MyStruc) 为 1+7+8+4+4=24 。其中总的有 7+4=11 个字节是 VC 自动填充的,没有放任何有意义的东西。
VC
对结构的存储的特殊处理确实提高
CPU
存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。
VC
中提供了
#pragma
pack(n)
来设定变量以
n
字节对齐方式。
n
字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果
n
大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果
n
小于该变量的类型所占用的字节数,那么偏移量为
n
的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果
n
大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为
n
的倍数。下面举例说明其用法。
#pragma pack(push) // 保存对齐状态
#pragma pack(push) // 保存对齐状态
#pragma
pack(4)//
设定为4字节对齐
struct
test
{
char
m1;double m4;int m3;
};
#pragma
pack(pop)//
恢复对齐状态
以上结构的大小为 16 ,下面分析其存储情况,首先为 m1 分配空间,其偏移量为 0 ,满足我们自
以上结构的大小为 16 ,下面分析其存储情况,首先为 m1 分配空间,其偏移量为 0 ,满足我们自
己设定的对齐方式(
4
字节对齐),
m1
占用
1
个字节。接着开始为
m4
分配空间,这时其偏移量为
1
,
需要补足
3
个字节,这样使偏移量满足为
n=4
的倍数(因为
sizeof(double)
大于
n
)
,m4
占用
8
个字节。
接着为
m3
分配空间,这时其偏移量为
12
,满足为
4
的倍数,
m3
占用
4
个字节。这时已经为所有成
员变量分配了空间,共分配了
16
个字节,满足为
n
的倍数。如果把上面的
#pragma pack(4)
改为
#pragma pack(16)
,那么我们可以得到结构的大小为
24
。(请读者自己分析)