相信很多coder在学习C语言(包括C++)的过程中都听说过这样的建议:慎用自增自减运算符。
这是因为,在函数参数或者表达式中多次调用自增自减运算符很可能产生“不可预知的结果”。究竟有多不可预知呢?请看这样一个程序
#include
int main()
{
int c, res;
c = 5;
res = (++c) + (++c);
printf("%d %d", c, res);
return 0;
}
首先定义变量c和res,给c赋值5,然后将(++c)+(++c)的值赋值给res,最后输出c和res。按照正常的思路:第一个(++c)先将c自增为6然后返回这个值6,第二个(++c)再将c自增为7并返回7,最后将6和7相加得到13赋给res。这样的话输出应该是这样的:
7 13
程序看似简单,但运行结果却很神奇:
7 14
c的输出和我们预想的一样,经过两次自增运算,5变成了7。但是,res的值就令人费解了,为什么会输出14呢?经过Simollus对程序反汇编的研究之后,发现了这样的问题。
这是反汇编的一个片段,注释是为方便理解改写成C语言样式:
6: c = 5;
00401028 mov dword ptr [ebp-4],5 //c = 5;
7: res = (++c) + (++c);
0040102F mov eax,dword ptr [ebp-4] //eax = c;
00401032 add eax,1 //eax +=1;
00401035 mov dword ptr [ebp-4],eax //c = eax;
00401038 mov ecx,dword ptr [ebp-4] //ecx = c;
0040103B add ecx,1 //ecx += 1;
0040103E mov dword ptr [ebp-4],ecx //c = ecx;
00401041 mov edx,dword ptr [ebp-4] //edx = c;
00401044 add edx,dword ptr [ebp-4] //edx += c;
00401047 mov dword ptr [ebp-8],edx //res = edx
可以发现,C语言的编译器犯了一个小小的“错误”,没有意识到c的值已经改变,在做最后的加法运算时调用了两次同样的c,导致结果成为7+7=14。当然,不同的编译器可能会犯不同的错误,也有可能不犯错误。
在这篇文章中有对于这种现象更为详细的例子分析。尽管我们可以了解并预知程序在不同编译器下会产生不同的结果,但是我认为最好的解决办法是:
不要连续使用自增自减运算符
注:本文所有程序均为在Visual C++ 6.0下编译运行,由于平台不同可能产生不同运行结果。
额。。我们老师教的方法是,先加1再使用.因为只有一个变量c,所以res = (++c) + (++c);先算后面那个++c,c变成6,再算前面那个++c,c变成7,然后再拿来使用,这样就14了。
这个,何必呢,在不同的编译器下可能会产生不一样的结果的,多写几行没有坏处,对吧
那这题答案中res到底是等于13还是14呢?
考试就要考这么变态的 没办法啦
考试的话就没有办法了,不过这种题目有够没有意义的。答案的话应该是14吧,毕竟编译之后的运行结果是14。
嗯!是14!
抱歉,vc是visual c++
visual:可视的
virtual:虚拟的
文章最后一行
多谢,已经改成。
今天使用这样一条语句,结果就来到了你的博客,呵呵,谢谢博主的分享。
使用串口打印数组中的连个字节发现输出的都是第一个字节的内容,语句如下:
hal_Printf1(“\r\na=%d b=%d”,*(pRate++),*(pRate++));
我没有去看汇编指令,不知道这里编译器是怎么处理的。
反正知道了最好不在一条语句里多次使用自增自减运算符。