Rumah > Soal Jawab > teks badan
篇幅有点长,让您受累了。。。
a++这个问题一直很困扰,自己做了个测试,虽然都知道a++是先使用
a再进行自加,疑问点就是这个a使用的期限是什么时候结束?一开始以为是表达式代码行完成后,在第二行代码需要试用a时,就是自加结果,这也是最常用的情况,也很好理解,如:
int a=0,b;
b=a++;
printf("a=%d b=%d",a,b);//输出:a=1,b=0
那假如在同一行表达式中出现2次a++,也就是说a++后又与其他变量进行运算,如下代码:
int a=10,b=0;
b=a+++a++;
printf("a=%d b=%d",a,b);//输出a=12 b=21
如果上面的理论成立那b应该等于20,根据执行结果显然不成立,所以我觉得应该是当执行a++运算时,a还是10,但当a在与其他变量继续运算时a就已经完成了自增,就是自增后的值与其他变量运算了,在变下代码再测试:
int a=10,b=0;
b=a+++b;//b=10(因为a++优先级大于++b,所以直观点应该是b=(a++)+b,尽管此时括号是多余的)
显然这种说法也不成立。
对b=a+++a++运算的猜测步骤为:
第一个a++ //此时a=10
第二个a++ //因为第一步运算完后a自增1,所以此时a=11,是第一个a++运算后的值
b=a+a //b=11+11=22,这点就不理解了,之所以最终结果这个b=21,难道是b=10+11吗,但中间+号的表达式两端都是a,应该两端的值都是一样的啊,应是22或20啊,怎么会是21,b=(a++)+(++a) 这个结果为22,应该可以说明+号两边都是a的话,第一个表达式a++中a会被++a后的值覆盖,所以b=11+11。
求解释b=a++a++的详细运算步骤,为啥会是b=21?
还有个问题:
int i=1;
int j=0;
for(;j<5;j++){
i=i++;
printf("i=%d",i);
}
printf("i=%d",i);
为什么i=1?为什么i=i++执行完后,在执行j<5之前或在下一轮执行前i没有自加?及时for循环中i=1,那for循环执行完后i应该至少会加1吧,起码i也得等于2啊?
PHP中文网2017-04-17 14:02:29
我以前学的时候也纠结过这些语法特性。 其实这个连起来写, 标准里面也没有定义要怎么样执行。
所以具体的结果依赖于编译器。 所以如果编译器不同, 具体的结果也可能不同。
所以实际中要避免这种写法, 避免出现坑爹的错误。
阿神2017-04-17 14:02:29
这类代码可以帮助我们理解c语言的一些规则,但是在实际工程里面最好不要出现这种写法,因为也许过了几个月你回头维护代码看到这里会觉得很困惑,或者别人维护你的代码更是有想掐死你的心情。好了,说说a+++a++吧,编译器编译的时候有个规则叫做贪心法,一次读入尽可能多的符号,那么开始可以一直读到a++,所以这个可以得出是(a++)+(a++),然而我用gcc4.5.1得出的结果却是20,可以看出来不同编译器编译结果是不同的,也许有优化吧。所以,再次重申,这种代码不要写到实际工程里面!能写一手整洁明了的代码才是优秀的程序猿。
阿神2017-04-17 14:02:29
我就是上文提到的链接的作者。
同时把当时分析时的图片也引过来一看便知:
反汇编代码在这里:
当然,这是vc++下,g++,clang的编译结果与此不同。
同时,还有之前另外回复的java和c++的运算顺序问题也供参考:
这个问题和运算符没有关系,都是从右往左计算,而是编译器对值类型的处理结果不一致导致的差异。
对于gc类语言来说,包括(java
,c#
,php
,javascript
)等,对于单句指令的中间运算结果会进行缓存。而C/C++由于直接编译为汇编指令,没有虚拟机或引擎的支持,所以不会有这一步。
通俗点来说,对于c++:
a=3*3;//9
a=a+a;//18
a=a-a;//0
也就是说a的值是值类型,会随时跟随a的变化而更新。无论初始设置a的值为几,结果都是0。(a-a).
然而对于其他语言,虚拟机或引擎会自动保存每一步的计算结果。
int a=3;
int result=0;
result=a*a;//9
result=a+result;//3+9=12
result=a-result;//3-12=-9
以上。
引申:PHP 一个诡异的加法算法的研究
大家讲道理2017-04-17 14:02:29
摘自 裘宗燕教授的的文章,应该是中文版最清晰的解释了。 http://www.math.pku.edu.cn/teachers/qiuzy/technotes/expression2009.pdf 楼上最佳答案从实现原理解释了结果,但如裘宗燕教授所指出,这个问题是规范层面的。不只是这类代码难以理解不要在项目中写,而是按照归范定义不能写。