background image

占用 sizeof(double)=8 个字节;接下来为第二个成员 dda 分配空间,这时下一个可以分配的地址对于结构
的起始地址的偏移量为 8,是 sizeof(char)的倍数,所以把 dda 存放在偏移量为 8 的地方满足对齐方式,
该成员变量占用 sizeof(char)=1 个字节;接下来为第三个成员 type 分配空间,这时下一个可以分配的地
址对于结构的起始地址的偏移量为 9,不是 sizeof(int)=4 的倍数,为了满足对齐方式对偏移量的约束问
题,VC 自动填充 3 个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起
始地址的偏移量为 12,刚好是 sizeof(int)=4 的倍数,所以把 type 存放在偏移量为 12 的地方,该成员变量
占用 sizeof(int)=4 个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:

8+1+3+4=16 , 刚 好 为 结 构 的 字 节 边 界 数 ( 即 结 构 中 占 用 最 大 空 间 的 类 型 所 占 用 的 字 节 数

sizeof(double)=8 ) 的 倍 数 , 所 以 没 有 空 缺 的 字 节 需 要 填 充 。 所 以 整 个 结 构 的 大 小 为 :

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;//偏移量为 0,满足对齐方式,dda 占用 1 个字节;

double dda1;//下一个可用的地址的偏移量为 1,不是 sizeof(double)=8

//的倍数,需要补足 7 个字节才能使偏移量变为 8(满足对齐

//方式),因此 VC 自动填充 7 个字节,dda1 存放在偏移量为 8

//的地址上,它占用 8 个字节。

int type;//下一个可用的地址的偏移量为 16,是 sizeof(int)=4 的倍

//数,满足 int 的对齐方式,所以不需要 VC 自动填充,type 存

//放在偏移量为 16 的地址上,它占用 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 自动填
充的,没有放任何有意义的东西。
  VC 对结构的存储的特殊处理确实提高 CPU 存储变量的速度,但是有时候也带来了一些麻烦,我们
也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。
  VC 中提供了#pragma pack(n)来设定变量以 n 字节对齐方式。n 字节对齐就是说变量存放的起始地址
的偏移量有两种情况:第一、如果 n 大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐
方式,第二、如果 n 小于该变量的类型所占用的字节数,那么偏移量为 n 的倍数,不用满足默认的对齐
方式。结构的总大小也有个约束条件,分下面两种情况:如果 n 大于所有成员变量类型所占用的字节数,
那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;
  否则必须为 n 的倍数。下面举例说明其用法。

#pragma pack(push) //保存对齐状态