设为首页 加入收藏

TOP

malloc与sizeof的合用的陷阱(二)
2014-11-23 21:42:12 来源: 作者: 【 】 浏览:51
Tags:malloc sizeof 合用 陷阱
sizeof能求静态分配的数组的大小,而特性4说明sizeof不能求的动态分配的内存的大小。于是有人认为sizeof是编译时进行求值的,并给出理由:语句int array[sizeof(int)*10];能编译通过,而很多书上都说过数组大小是编译时就确定下来的,既然前面的语句能编译通过,所以认为sizeof是编译时进行求值的。经过进一步测试我发现这个结论有些武断!至少是有些不严谨!因为在实现了c99标准的编译器(如DEV C++)中可以定义动态数组,即:语句:int num;cin>>num; int arrary[num];是对的(注意在vc6.0中是错的)。因此我就在DEV C++中对刚才的array利用语句int n=sizeof(array);cout<
那么到底sizeof是编译时求值还是运行时求值呢?最开初c标准规定sizeof只能编译时求值,后来c99又补充规定sizeof可以运行时求值。但值得注意的是,即便是在实现了c99标准的DEV C++中仍然不能用sizeof求得动态分配的内存的大小!
特性5:sizeof不能对不完整的数组求长度!
在阐述该特性之前,我们假设有两个源文件:file1.cpp和file2.cpp,其中file1.cpp中有如下的定义:
int arrayA[10] = {1,2,3,4,5,6,7,8,9,10};
int arrayB[10] = {11,12,13,14,15,16,17,18,19,20};
file2.cpp包含如下几个语句:
externarrayA[];
externarrayB[10];
cout<
cout<
在file2.cpp中第三条语句编译出错,而第条语句正确,并且能输出40!为什么呢?原因就是sizeof(arrayA)试图求不完整数组的大小。这里的不完整的数组是指数组大小没有确定的数组!sizeof运算符的功能就是求某种对象的大小,然而声明:extern int arrayA[]只是告诉编译器arrayA是一个整型数组,但是并没告诉编译器它包含多少个元素,因此对file2.cpp中的sizeof来说它无法求出arrayA的大小,所以编译器干脆不让你通过编译。
那为什么sizeof(arrayB)又可以得到arraryB的大小呢 关键就在于在file2.cpp中其声明时使用externint arrayB[10]明确地告诉编译器arrayB是一个包含10个元素的整型数组,因此大小是确定的。
到此本特性讲解差不多要结束了。其实本问题还能引申出连接和编译等知识点,但是目前我暂时还没自信对这两个知识点进行详细的,彻底的讲解,因此不便在此班门弄斧,不久的将来我会在本系列中加上相关问题的阐述。
特性6:当表达式作为sizeof的操作数时,它返回表达式的计算结果的类型大小,但是它不对表达式求值!
为了说明这个问题,我们来看如下的程序语句:
char ch = 1;
int num=1;
int n1 =sizeof(ch+num);
int n2 = sizeof(ch =ch+num);
假设char占用1byte,int占用4byte,那么执行上面的程序之后,n1,n2,ch的值是多少呢?我相信有不少人会认为n1与n2相等,也有不少人认为ch等于2,事实这些人都错了。事实上n1等于4,n2等于1,ch等于1,为什么呢?请看分析:
由于默认类型转换的原因,表达式ch+num的计算结果的类型是int,因此n1的值为4!而表达式ch=ch+num;的结果的类型是char,记住虽然在计算ch+num时,结果为int,但是当把结果赋值给ch时又进行了类型转换,因此表达式的最终类型还是char,所以n2等于1。n1,n2的值分别为4和1,其原因正是因为sizeof返回的是表达式计算结果的类型大小,而不是表达式中占用最大内存的变量的类型大小!
对于n2=sizeof(ch=ch+num);乍一看该程序貌似实现了让ch加上num并赋值给ch的功能,事实并非如此!由于sizeof只关心类型大小,所以它自然不应该对表达式求值,否则有画蛇添足之嫌了。正是因为这点,这里告诫各位,尽量不要在sizeof中直接对表达式求大小,以免出现错误,你可以将sizeof(ch = ch+num);改写成 ch = ch +num;sizeof(ch);虽然多了一条语句,看似冗余了,其实好处多多:首先更加清晰明了,其次不会出现ch等于1这样的错误(假设程序的逻辑本身就是要执行ch = ch +num;)。
特性7:sizeof可以对函数调用求大小,并且求得的大小等于返回类型的大小,但是不执行函数体!
假设有如下函数(是一个写得很不好的函数,但是能很好的说明需要阐述的问题):
int fun(int& num,const int& inc)
{
float div = 2.0;
double ret =0;
num = num+inc;
ret = num/div;
return ret;
}那么语句:
int a = 3;
int b = 5;
cout<
cout<
首先sizeof(fun(a,b))的值:其正确是4,因为用sizeof求函数调用的大小时,它得到的是函数返回类型的大小,而fun(a,b)的返回类型是int,sizeof(int)等于4。很多人把函数的返回类型和返回值的类型弄混淆了,认为sizeof(fun(a,b))的值是8,因为函数返回值是ret,而ret被定义成double,sizeof(doube)等于8。注意,虽然函数返回值类型是double,但是在函数返回时,将该值进行了类型转换(这里的转换不安全)。也有人错误的认为sizeof(fun(a,b))的值是12,它们的理由是:fun内部定义了两个局部变量,一个是float一个是double,而sizeof(float)+sizeof(doube)= 4+8=12。这样的答案看似很合理,其实他们是错误地认为这里的sizeof是在求函数内部的变量的大小了。这当然是错误的。
接下来看a的值:其正确答案是3!还记得特性6吗?这里很类似,sizeof的操作对象是函数调用时,它不执行函数体!为此,建议大家不要把函数体放在sizeof后面的括号里,这样容易让人误以为函数执行了,其实它根本没执行。
既然对函数条用使用sizeof得到的是函数返回类型的大小,那么很自然能得出这样的结论:不能对返回类型为void的函数使用sizeof求其大小!原因请参考特性1。同理,对返回类型是任何类型的指针的函数调用使用sizeof求得的大小都为4,原因请参考特性2。
最后我们来看看这样的语句:cout<
特性8:sizeof求得的结构体(及其对象)的大小并不等于各个数据成员对象的大小之和!
结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体A、B使用sizeof的结果分别是:16,24。
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言的那些事――scanf()和gets(.. 下一篇Linux环境下的C/C+基础调试技术2..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: