现在的位置: 首页 > 综合 > 正文

struct 字节对齐详解

2018年05月19日 ⁄ 综合 ⁄ 共 2428字 ⁄ 字号 评论关闭

现在已知32位机器上各种数据类型的长度如下:
char:1(有符号无符号同)    
short:2(有符号无符号同)    
int:4(有符号无符号同)    
long:4(有符号无符号同)    
float:4  

double:8

 

先让我们看几个例子(32bit,x86环境,gcc编译器):
设结构体如下定义:
struct A
{
    int a;
    char b;
    short c;
};
struct B
{
    char b;
    int a;
    short c;
};
那么上面两个结构大小如何呢?
结果是:
sizeof(strcut A)值为8
sizeof(struct B)的值却是12

这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结
构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。

详解:

        Char      偏移量必须为sizeof(char)即1的倍数

Short     偏移量必须为sizeof(short)即2的倍数
int   偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double  偏移量必须为sizeof(double)即8的倍数
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。同时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 中提供了#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个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。

sizeof用法总结

    A.
int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小

        int *a=new int[50];// sizeof(a)=4; a为一个指针,sizeof(a)是求指针的大小,在32位系统中,当然是占4个字节。

B. 参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意:

        第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。

第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。
下面举例说明,
Class Test{int a;static double c};//sizeof(Test)=4.
Test *s;//sizeof(s)=4,s为一个指针。
Class test1{ };//sizeof(test1)=1;
C. 参数为其他。下面举例说明。
 int func(char s[5]);
 {
 cout< //数的参数在传递的时候系统处理为一个指针,所以sizeof(s)实际上为求指针的大小。
 return 1;
}
sizeof(func(“1234”))=4//因为func的返回类型为int,所以相当于求sizeof(int).

抱歉!评论已关闭.