可能重复:
Compilers and argument order of evaluation in C++
cout << order of call to functions it prints?
此:
int k=3;
printf("%d %d %d",k++,k,++k);
输出为4 4 4
,因为它们被推入堆栈中:
%d%d%d
4 -- for k++
4 --for k
4 --for ++k
右
此:
int k = 3;
cout << k++ << k << ++k;
实际上是重复的函数调用,所以它相当于:
( ( (cout << k++) << k) << ++k);
所以,我想首先k++
然后k
然后++k
必须始终按此顺序执行,对吧?我相信函数调用是一个序列点,但输出在不同的实现上有所不同。为什么会这样?
答案 0 :(得分:7)
标准评估参数的顺序是未指定。这意味着,它可以按照实现的任何顺序发生。
答案 1 :(得分:4)
这是未定义的,因为在printf语句中没有序列点。如果没有序列点,编译器可以按原样顺序写入内存位置k
。
现在你可能想知道“这到底是什么意思”,为什么它有关系?基本上,序列点是代码中的一个点,其中有问题的内存位置,在这种情况下k
最多被修改一次。这里有一个更全面的描述:https://isocpp.org/wiki/faq/misc-technical-issues#double-mod-betw-seq-pt
从FAQ中可以看出,printf中的,
没有引入序列点。
在cout
的情况下,这是不同的,因为对operator >>
有3个函数调用。函数调用引入了一个序列点,因此对内存位置k
的修改具有已定义的顺序。然而(这是我错过的一点,但Cubbi指出)因为C / C ++没有定义函数参数的评估顺序,即使它们是函数,这些参数也可以按编译器定义的任何顺序进行评估。所以在表达式中:
f(h(), g())
首先评估h()或g()是否未定义:http://www.stroustrup.com/bs_faq2.html#undefined。所以这就是为什么即使在cout的情况下你从不同的编译器得到不同的结果,主要是因为cout << k++ << k << ++k
转换为cout.operator<<(k++).operator<<(k).operator(++k)
实际上是这样的表达式:f(h(g(cout, k++), k), ++k)
和每个函数参数都以未指定的顺序进行评估。
答案 2 :(得分:2)
您的答案涵盖了对printf
的调用,但您也在问为什么cout
语句的输出在编译器之间有所不同。
你说它等同于
是正确的( ( (cout<<k++)<<k)<<++k);
现在,要评估该表达式并获得其结果,编译器必须评估最右边的<<
。在对<<
进行函数调用之前,必须对其两个操作数( (cout<<k++)<<k)
和++k
进行求值。并且这两个评估可以以任何顺序发生,或者甚至同时发生(编译器经常交错来自两个独立的(如编译器认为的)代码分支的cpu指令。
由于对两个表达式的评估都涉及写入k
,因此在cout的情况下,行为也是未定义的。
答案 3 :(得分:0)
实际上,printf和cout都是&lt;&lt;是函数调用,C ++和C不定义参数的评估顺序。因此,从编译器到编译器,这些测试用例的结果会有所不同,因为它的实现是定义的。