运行结果取决于未定义行为的一些不良写法,可总有人拿出来当题考别人。。。
首先printf()函数里面参数的求值顺序,标准C里只规定了四个运算符的求值顺序,||,&&,?:,还有逗号,但不是函数参数表里的逗号。
基于任何关于函数参数求值顺序的假设都是危险的行为。
至于printf的求值顺序在VC6.0和Gcc里面都是从右到左的。
所以第一个printf的输出两个编译器是相同的?NO。。。
还有一个++和--运算符的问题。。。。
在VC6.0中的输出是
3,2
在GCC中的输出是
4,2
分别进行反汇编,观察一下就明了了,VC6.0中的disassembly
可以明白地址为ebp-4的内存就是存储变量b的地方,传参的时候,先做了一份拷贝放入eax中,然后又拷贝到ebp-8,然后ebp-8又拷贝到ecx,最后将ecx压入栈中。然后将b的值拷贝到edx,进行++b,操作完之后更新b的值,然后把更新过的值拷贝到eax中,并且入栈。
所有参数入栈之后,将b的值再放入ecx中,进行b++,然后更新b的值,然后调用函数。。。
实际上的结果同
int b,a;
a=b=2;
++b;
printf("%d,%d/n",b,a);
a++;
然后是GCC,GCC中的反汇编器的结果是
汇编代码比VC的简单一些
继续,语句改成
printf("%d,%d/n",b++,++b);
结果是多少呢
VC6.0中为
3,3
GCC中为
3,4
VC6.0的反汇编结果
不管b++的位置在左边还是右边,在VC6.0中是全部参数入栈之后调用函数之前更新b的值
在GCC中的反汇编结果
在GCC中,b++作为参数,是在保存了b更新前的值之后,就立刻进行b++。。。当然是在参数入栈之前
printf("%d,%d",b++,b++);的结果呢
利用上面的分析
VC6.0中应该是2,2
GCC中应该是3,2
事实也的确是这样的。。。。
再来一个问题,
int b=2;
int a1=++b+(++b);
a1的值是多少?
a2=++b+(b++)呢?
a3=b+++(++b)呢?
VC6.0中
a1的值为8
a2的值为6
a3的值为6
a2为例,反汇编器结果,实际上a3的结果也是一样的,优先计算++b么??
在GCC中结果是一样的。。。
结论
1)在VC6.0中,不管b++的位置在左边还是右边,全部参数入栈之后,调用函数之前,b++才会进行。
2)在GCC: (GNU) 4.2.4中,b++作为参数,是在保存了b更新前的值之后,就进行b++操作,并更新b的值,是在参数入栈之前。
3)上述都是不好的行为,旨在自虐和练习读汇编。