VC中结构体内存分配问题透析
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
结构体变量分配内存时与 C 语言不同:VC++中为结构体分配内存时,先分配一单位长度(该单位长度的大小等于结构体
中占内存最多数据类型,如 struct2 的单位长度为数据类型 long 的长度 4。),然后在该单位长度中依次为结构中的变量
分配空间,直至该单位空间不能再分配完一个完整的变量时为止,就再为该结构体分配另一个单位长度的存储空间。如
中运行上述两个例子中的程序,得到的结果都是 the size of the struct=7。这是由于 char 数据类型的长度是 1,long 数
据类型的长度是 4,而 short int 数据类型的长度是 2,从而得到 1+2+4=7。
那么为什么上述两个例子在 VC++环境下所得的结果各不相同并且均不是 7 呢?在实际应用中,我们发现 VC++中为
struct=%d\n″,
sizeof(struct2));
运行结果是:the size of the struct=12
问题:显然上述两个程序的运行结果是不同的。然而仔细观察上述两个程序,它们的唯一区别是变量 p2 在结构体 struct
struct1 和 struct struct2 中的位置不同。而这一不同是如何导致程序运行结果不同呢?
sizeof(struct1));
运行结果是:the size of the struct=8
程序 2:
#include <stdio.h> struct struct2 { char p1; long p3; short int p2; }; main() {printf(″the size of the return(1); }
为该结构体分配 4 个字节,该 4 个字节恰好是 p3 所需的,所以 struct1 共有 4+4=8 个字节。
至此我们便不难理解上述两个例子中的结果是如何算出来的。其中wenku.baidu.com例 1 中是 4+4=8,而例 2 中是 4+4+4=12。
三、实战
//(1)、 struct structData1 {
int i; char ch; double d; short s; float f; long l; }; sizeof(struct structDate1) 空)=32 //(2)、 struct structData2 { short int s1; char ch1; short int s2; char ch2; }; sizeof(struct structDate2) =8 //(3)、 struct structData3 { int s1; char ch1; short int s2; char ch2; }; sizeof(struct structDate3)
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。(请读者自己分析) 2、 sizeof 用法总结 在 VC 中,sizeof 有着许多的用法,而且很容易引起一些错误。下面根据 sizeof 后面的参数对 sizeof 的用法做个总结。 A. 参数为数据类型或者为一般变量。例如 sizeof(int),sizeof(long)等等。这种情况要注意的是不同系统系统或者不同编 译器得到的结果可能是不同的。例如 int 类型在 16 位系统中占 2 个字节,在 32 位系统中占 4 个字节。 B. 参数为数组或指针。下面举例说明. int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小 int *a=new int[50];// sizeof(a)=4; a 为一个指针,sizeof(a)是求指针 //的大小,在 32 位系统中,当然是占 4 个字节。 C. 参数为结构或类。Sizeof 应用在类和结构的处理情况是相同的。但有两点需要注意,第一、结构或者类中的静态成 员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。 第二、没有成员变量的结构或类的大小为 1,因为必须保证结构或类的每一 个实例在内存中都有唯一的地址。 下面举例说明, Class Test{int a;static double c};//sizeof(Test)=4. Test *s;//sizeof(s)=4,s 为一个指针。 Class test1{ };//sizeof(test1)=1; D. 参数为其他。下面举例说明。 int func(char s[5]); { cout< //数的参数在传递的时候系统处理为一个指针,所 //以 sizeof(s)实际上为求指针的大小。 return 1; } sizeof(func(“1234”))=4//因为 func 的返回类型为 int,所以相当于 //求 sizeof(int). 以上为 sizeof 的基本用法,在实际的使用中要注意分析 VC 的分配变量的分配策略,这样的话可以避免一些错误。
一、问题提出
首先,我们来看以下两个小程序:
程序 1:
#include <stdio.h> struct struct1 { char p1; short int p2; long p3; }; main() { printf(″the size of the strcu=%d\n″, return(1); }
齐方式对偏移量的约束问题,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) //保存对齐状态 #pragma pack(4)//设定为 4 字节对齐 struct test { char m1;
二、VC++中的结构体分析
C 语言提供了一种称为结构体的数据类型,它可以将不同类型的数据组合成一个有机整体,这样不但便于引用,而且
很清楚地反映出各数据项之间的内在联系,因而在 C 语言中结构体得到广泛的应用。正如我们已经熟知的那样,在 C
语言中,结构体的长度等于各数据项长度之和,而且结构体的长度与数据项在其中的位置顺序无关。例如,在 TurboC
=(4+1+3 空)+(8)+(2+4+2 空)+(4+4 =(2)+(1+1 空)+(2)+(1+1 空) =(4)+(1+2+1 空)+(1+3 空)=12
------------------------------------------------------------------------------------------------------------------------------------------------
结构体 struct2:首先,分配 4 个字节,p1 占 1 个字节后,剩余的 3 个字节不足以分配 p3,于是,系统为 struct2 再分配
4 个字节分给 p3,接着下 4 个字节分给 p2,把以,struct2 共有 4+4+4=12 个字节。再如结构体 struct1:同样先分配 4
个字节,p1 占 1 个字节后,还可为 p2 分配 2 个字节,显然剩余的 1 个字节不足以为 p3 分配空间了,因此系统还要再
VC 中结构体内存分配问题透析(sizeof)
本文首先提出了处理 VC++中结构体时应注意的一个问题,然后详细分析了存在该问题的原因,最后做实战训练。 注意: (1)在 VC 下,下面各类型占字节数为:char->unsigned int ->1; short int ->2; int ->unsigned int ->4; long
->float->4; double ->long double ->8 (2)在 TC 下,下面各类型占字节数为:char->unsigned int ->1; short int ->2; int ->unsigned int ->2; long
->float->4; double ->8; long double ->10
本文主要包括二个部分,第一部分重点介绍在 VC 中,怎么样采用 sizeof 来求结构的大小,以及容易出现的问题,并给 出解决问题的方法,第二部分总结出 VC 中 sizeof 的主要用法。 1、 sizeof 应用在结构上的情况 请看下面的结构: struct MyStruct { double dda1; char dda; int type }; 对结构 MyStruct 采用 sizeof 会出现什么结果呢?sizeof(MyStruct)为多少呢?也许你会这样求: sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13 但是当在 VC 中测试上面结构的大小时,你会发现 sizeof(MyStruct)为 16。你知道为什么在 VC 中会得出这样一个结果 吗? 其实,这是 VC 对变量存储的一个特殊处理。为了提高 CPU 的存储速度,VC 对一些变量的起始地址做了“对齐”处理。 在默认情况下,VC 规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节 数的倍数。下面列出常用类型的对齐方式(vc6.0,32 位系统)。 类型 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量) Char 偏移量必须为 sizeof(char)即 1 的倍数 int 偏移量必须为 sizeof(int)即 4 的倍数 float 偏移量必须为 sizeof(float)即 4 的倍数 double 偏移量必须为 sizeof(double)即 8 的倍数 Short 偏移量必须为 sizeof(short)即 2 的倍数 各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节 VC 会自动填充。同时 VC 为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的 倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。 下面用前面的例子来说明 VC 到底怎么样来存放结构的。 struct MyStruct { double dda1; char dda; int type }; 为上面的结构分配空间的时候,VC 根据成员变量出现的顺序和对齐方式,先为第一个成员 dda1 分配空间,其起始地址 跟结构的起始地址相同(刚好偏移量 0 刚好为 sizeof(double)的倍数),该成员变量占用 sizeof(double)=8 个字节;接 下来为第二个成员 dda 分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为 8,是 sizeof(char)的倍 数,所以把 dda 存放在偏移量为 8 的地方满足对齐方式,该成员变量占用 sizeof(char)=1 个字节;接下来为第三个成员 type 分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为 9,不是 sizeof(int)=4 的倍数,为了满足对