C语言函数参数中的表达式顺序问题

来源:互联网 发布:java notempty 编辑:程序博客网 时间:2024/04/30 10:27

偶然一次遇到一个C程序,代码如下:

#include <stdio.h>int main(){int a = 1, b = 1;printf("%d,%d\n", (a++, --b), b - 1);return 0;}
不知为何,大家在讨论这个问题的时候出现了分歧,有人说程序输出的是0,0,也有人说程序输出的是0,-1。这个问题,运行试试不就知道了吗,搞得这么复杂。

结果,不看不知道,一看吓一跳。gcc编译之后会输出0,0,VS2013下得到的结果却是0,-1,。这,未免有点儿吓人。这引起了我极大的兴趣,按理说,函数参数的表达式计算的顺序默认应该是从右往左;比如:

fun(f1(),f2());
这样的代码,f2会先被调用,其次是f1。而遇到逗号表达式

a=(f1(),f2());
这样的东西时,默认应该是先执行f1,然后是f2。最后a的值取f2的返回值。

这样的话,在gcc中就能解释的通了,先计算b-1得到0,作为参数传入printf,然后,计算(a++,--b),注意这时候b的值是1,所以(a++,--b)的值也是0。因此printf输出0,0。

但是在VS中却出现了不同的结果,输出了0,-1。满怀好奇心的我打开了VS的调试,进入了反汇编。

     6: printf("%d,%d\n", (a++, --b), b - 1);004153CC  mov         eax,dword ptr [a]  004153CF  add         eax,1  004153D2  mov         dword ptr [a],eax  004153D5  mov         ecx,dword ptr [b]  004153D8  sub         ecx,1  004153DB  mov         dword ptr [b],ecx  004153DE  mov         edx,dword ptr [b]  004153E1  sub         edx,1  004153E4  push        edx  004153E5  mov         eax,dword ptr [b]  004153E8  push        eax  004153E9  push        436DC0h  004153EE  call        _printf (0412B6Dh)  004153F3  add         esp,0Ch  
为便于阅读,笔者开启了符号显示。我们可以看到,在VS2013中,先执行了a++,然后是--b,然后才是将b-1送入printf!!!

这个问题变得复杂起来了,如果函数有多个参数,每个参数都含有逗号表达式。想到这里,笔者不禁一阵冷汗。算了,试试吧。

于是笔者写下这样的代码:

#include <stdio.h>int f(int x){printf("%d", x);return x;}int main(){int a = 1, b = 1;printf("\n%d %d\n", (f(2), f(3)), (f(4), f(5), f(6)));return 0;}


gcc编译后输出的结果是这样的:

456233 6
而VS2013中却输出了这样的结果:

452633 6
顺序不一样!!!到了这里笔者已经不想再折腾,我想读者你也应该已经看到,在gcc和VS中各表达式依次执行的顺序。

不知道细心的读者是否注意到了,以上的代码在VS中出现了冲突(对比第一个代码和第二个代码在VS中的执行顺序,你会发现两者不一致!!)。笔者已不想再折腾,就简单说一下gcc中总结的结果吧。gcc中,是按照函数参数从右至左,逗号表达式中从左至右的顺序执行的。并且逗号表达式的值为最右边的表达式的值。而在VS中,逗号表达式的取值方式依然没有变化,但是执行的顺序却十分奇怪。

在这里,笔者想要说明的就是,在实际写代码的过程中,千万不要装X写这样的作死的代码,可移植性有待考究。在不同的编译环境下得到了不一样的结果,这在实际编程中是不能被接受的。

当然,这样的问题也不止一个,总之,笔者的建议,尽量写标准,规范,可读性高,可移植性好的代码。一句话:“装X一时爽,调试火葬场”。

谢谢。

0 0