cout vs printf – 执行顺序
可能重复:
C ++中编译器和评估的参数顺序
cout <<打印函数的调用顺序?
-
这个:
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
必须始终按此顺序执行,对吧? 我相信函数调用是一个序列点,但输出在不同的实现上有所不同。 为什么会这样?
这是未定义的,因为在printf语句中没有序列点。 如果没有序列点,编译器可以自由地按顺序对存储器位置k
进行排序。
现在你可能想知道’到底是什么意思点’,为什么它有关系? 基本上,序列点是代码中的一个点,其中所讨论的存储器位置,在这种情况下k
最多被修改一次。 这里有一个更全面的描述: https : //isocpp.org/wiki/faq/misc-technical-issues#double-mod-betw-seq-pt
从FAQ中可以看出,
printf中没有引入序列点。
在cout
的情况下,这是不同的,因为有3个函数调用operator >>
。 函数调用引入序列点,因此对存储器位置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)
并且每个函数参数以未指定的顺序计算。
参数的评估顺序未由标准指定 。 这意味着,它可以按照实现的任何顺序发生。
你有答案覆盖了对printf
的调用,但你也问为什么cout
语句的输出在编译器之间有所不同。
你说它等同于你是对的
( ( (cout<
现在,为了评估该表达式并获得其结果,编译器必须评估最右边的<<
。 在函数调用<<
之前,必须对它的两个操作数( (cout<
++k
进行求值。 并且这两个评估可以以任何顺序发生,或者甚至同时发生(编译器经常交错来自两个独立的(如编译器认为的)代码分支的cpu指令。并且由于两个表达式的评估涉及写入k
,所以行为是不确定的,以防万一也是这样的。
实际上,printf和cout <<都是函数调用,而C ++和C都没有定义参数的评估顺序。 因此,这些测试用例的结果因编译器而异,因为它的实现已定义。