sizeof超级宝典

来源:互联网 发布:公交车线路查询软件 编辑:程序博客网 时间:2024/05/08 00:20

      我们大家对sizeof() 并不陌生吧,在C系列语文的编程中用来求内存大小的函数, 即内存所占的字节数(byte)。如:

    int a,b;

    b = sizeof() ;

如果在32位的OS上b=4,因为a是int型,占32位即4字节。相应的float也是4,short是2,char是1,double为8。如果是16位的OS占的字节数都除以2, 64位则乘以2,以此类推。int ,short,char这些都是基本数据类型,当然用sizeof所得的结果都是固定的。

 

      有时候我们需要自定义数据类型的大小,上面的方法行得通吗?

如:

struct example

{

int a;

char b;

double c;

};

可能你会想 sizeof(example) == sizeof(a)+sizeof(b)+sizeof(c) = 4+1+8 =13, 其实在大多数情况下它都不是13的, 在VC环境下测试所得的结果将会是16。因为大部份编译器会对变量的存储做特殊处理:为了提高CPU的存取速度,编译器对变量的起始地址做了对齐的处理。VC也这样做了,它规定各成员变量存放的地址相对于结构体的起始地址的偏移量必须为此变量的类型所占用的字节数的整数倍,而整个结构体所占空间为结构中占用最大空间的类型所占用的字节数的整数倍。下面给出VC6+XP下各基本类型存放时相对于结构体起始位置的偏移量。

 

char      1的倍数(自然数)

int         4的位数

float      4的位数

double   8的位数

 

下面我们来分析一下16是如何得到的。我们在为结构体分配空间的时候,VC将根据变量的顺序一个一个对齐。首先分配第一个数据int a,因为是第一个数据所以地址与结构体起始地址相同,即偏移地址为0(0是4的整数倍)。接着我们为第二个数据b分配空间,因为b是float型,它的偏移量是1的倍数,而前面存放了4节字的a,所以我们紧接着a后面存放b。最后我们分配c, 因为c是double,它的偏移量是8的倍数,而存放a与b花了5字节的空间,b后面的地址的偏移量是5,5不是8的倍数,所以VC将自动填充3个字节使偏移量到8(满足8的整数倍)。些时结构体所有变量空间分配完成,即4+1+3+8 = 16。而16为sizeof(c)的整数倍,所以该结构体所占用空间为16字节。填充的3字节不存放任何东西,而我们也无法使用。

 

    虽然这种处理提高了速度,但是有实际应用中会遇到很多麻烦。例如不同OS间通信的时候。有的时候我不需要编译器的默认处理。VC中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;

 如:

#pragma pack(push) //保存对齐状态
#pragma pack(1)//设定为1字节对齐

struct example

{

int a;

char b;

double c;

};

#pragma pop();

些时sizeof(example) == 4+1+8 =13

 

#pragma pack(push) //保存对齐状态
#pragma pack(4)//设定为1字节对齐

struct example

{

int a;

char b;

double c;

};

#pragma pop();

些时sizeof(example) == 4+1+3+8 =16

 

  1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
  2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
  3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

原创粉丝点击