龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

C语言内存对齐实例详解(2)

时间:2014-09-11 11:21来源:网络整理 作者:网络 点击:
分享到:
下面再举个例子,交换一下上面的struct1的成员变量的位置,使它变成下面的情况: struct mystruct2{ char cda; double dda; int ida;}; 运行结果为:24 struct mystruct2{

下面再举个例子,交换一下上面的struct1的成员变量的位置,使它变成下面的情况:

struct mystruct2
{
  char cda;
  double dda;
  int ida;
};

 运行结果为:24

struct mystruct2
{
  char cda;  //偏移量为0,满足对齐方式,cda占用1个字节;
  double dda; //下一个可用的地址的偏移量为1,不是sizeof(double)=8 
         //的倍数,需要补足7个字节才能使偏移量变为8(满足对齐 
         //方式),因此VC自动填充7个字节,dda存放在偏移量为8 
         //的地址上,它占用8个字节。 

  int ida;   //下一个可用的地址的偏移量为16,是sizeof(int)=4的倍 
         //数,满足int的对齐方式,所以不需要VC自动填充,type存 
         //放在偏移量为16的地址上,它占用4个字节。
  
  //所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构 
  //的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof 
  //(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为 
  //sizeof(double)=8的倍数。
};

所以该结构总的大小为:sizeof(struct2)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。

二、#pragma pack(n)来设定变量以n字节对齐方式

VC对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:

第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式;

第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。下面举例说明其用法:

#pragma pack(push) //保存对齐状态 
#pragma pack(4)//设定为4字节对齐 
struct test 
{ 
  char m1; 
  double m4; 
  int m3; 
}; 
#pragma pack(pop)//恢复对齐状态 

以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为 m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了4+8+4=16个字节,满足为n的倍数。如果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。

再看下面这个例子:

#pragma pack(8)
struct S1{
  char a;
  long b;
};
struct S2 {
  char c;
  struct S1 d;
  long long e;
};
#pragma pack()

成员对齐有一个重要的条件,即每个成员分别对齐.即每个成员按自己的方式对齐.

也就是说上面虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐.其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是8字节)中较小的一个对齐.并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节.

S1中,成员a是1字节默认按1字节对齐,指定对齐参数为8,这两个值中取1,a按1字节对齐;成员b是4个字节,默认是按4字节对齐,这时就按4字节对齐,所以sizeof(S1)应该为8;

S2 中,c和S1中的a一样,按1字节对齐,而d 是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,S1的就是4.所以,成员d就是按4字节对齐.成员e是8个字节,它是默认按8字节对齐,和指定的一样,所以它对到8字节的边界上,这时,已经使用了12个字节了,所以又添加了4个字节的空,从第16个字节开始放置成员e.这时,长度为24,已经可以被8(成员e按8字节对齐)整除.这样,sizeof(S2)为24个字节.

这里有三点很重要:

1.每个成员分别按自己的方式对齐,并能最小化长度。

2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。

3.对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。

三、minix的stdarg.h文件中对齐方式

精彩图集

赞助商链接