资源描述:
《结构体内存分配分析》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库。
1、结构体成员的内存分布与对齐马国峻maguojun2005@sina.com我们先看一道IBM和微软的笔试题:IBM笔试题:struct{ short a1;short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A)=6, sizeof(B)=8,为什么? 注:sizeof(short)=2,sizeof(long)=4微软笔试题:structexample1{shorta;longb;};structexample2{charc;example1struct1;shorte;};intmain(intargc,ch
2、ar*argv[]){example2e2;intd=(unsignedint)&e2.struct1-(unsignedint)&e2.c;printf("%d,%d,%d",sizeof(example1),sizeof(example2),d);return0;}输出结果?要能清除的分析上面的问题就要搞清楚结构体变量的成员在内存里是如何分布的、成员先后顺序是怎样的、成员之间是连续的还是分散的、还是其他的什么形式?其实这些问题既和软件相关又和硬件相关。所谓软件相关主要是指和具体的编程语言的编译器的特性相关,编译器为了优化CPU访问内存的效率,在生成结构体成员的起始地址时遵循着某种特
3、定的规则,这就是所谓的结构体成员“对齐”;所谓硬件相关主要是指CPU的“字节序”问题,也就是大于一个字节类型的数据如int类型、short类型等,在内存中的存放顺序,即单个字节与高低地址的对应关系。字节序分为两类:Big-Endian和Little-Endian,有的文章上称之为“大端”和“小端”,他们是这样定义的:Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。Intel、VAX和Unisys处理器的计算机中的数据的字节顺序是Little-Endian,IBM大型
4、机和大多数Unix平台的计算机中字节顺序是Big–Endian。关与Big-Endian和Little-Endian问题本文暂不做详细讨论,本文将以小端机(此处为intelx86架构的计算机)、OS:WindowsXp和VC++6.0编译器来详细讨论结构体成员的“对齐”问题。前面说了,为了优化CPU访问内存的效率,程序语言的编译器在做变量的存储分配时就进行了分配优化处理,优化规则大致原则是这样: 对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,这种原则称为“对齐”,如WORD(2字节)的值应该能被2整除的位置,DWORD(4字节)应该在能被4整除的位置。 对于结构体来说,
5、结构体的成员在内存中顺序存放,所占内存地址依次增高,第一个成员处于低地址处,最后一个成员处于最高地址处,但结构体成员的内存分配不一定是连续的,编译器会对其成员变量依据前面介绍的“对齐”原则进行处理。对待每个成员类似于对待单个n字节的元素一样,依次为每个元素找一个适合的首地址,使得其符合上述的“对齐”原则。通常编译器中可以设置一个对齐参数n,但这个n并不是结构体成员实际的对齐参数,VC++6.0中结构体的每个成员实际对齐参数N通常是这样计算得到的N=min(sizeof(该成员类型),n)(n为VC++6.0中可设置的值)。成员的内存分配规律是这样的:从结构体的首地址开始向后依次为每个成员寻
6、找第一个满足条件的首地址x,该条件是x%N=0,并且整个结构的长度必须为各个成员所使用的对齐参数中最大的那个值的最小整数倍,不够就补空字节。结构体中所有成员的对齐参数N的最大值称为结构体的对齐参数。VC++6.0中n默认是8个字节,可以修改这个设定的对齐参数,方法为在菜单“工程”的“设置”中的“C/C++”选项卡的“分类”中“CodeGeneration”的“Structmemberalignment”中设置,1byte、2byte、4byte、8byte、16byte等几种,默认为8byte也可以程序控制,采用指令:#pragma pack(xx)控制如#pragma pack(1),1
7、字节对齐,#pragma pack(4),4字节对齐#pragma pack(16),16字节对齐接下来我们将分不同的情况来详细讨论结构体成员的分布情况,顺便提醒一下,常见类型的长度:Int4byte,Short2byte,Char1byte,Double8byte,Long4byte让我们先看下例:structA{charc;//1bytedoubled;//8byteshorts;//2byteinti;//4byt