解释 printf 中的评估顺序 [重复]

Posted

技术标签:

【中文标题】解释 printf 中的评估顺序 [重复]【英文标题】:Explain the order of evaluation in printf [duplicate] 【发布时间】:2012-10-09 05:47:17 【问题描述】:
main()

    int i=5;
    printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);

输出是 45545,但我不知道它是如何工作的。有人说函数调用中的参数是从左到右压入堆栈的。

【问题讨论】:

小心,你有 6 个格式指定器 %d 并且只有 5 个参数... 对参数通过堆栈传递的概念要非常小心。现代编译器试图通过寄存器传递尽可能多的参数。 因为评估是从右到左开始的 在 g++ 中是,在 Visual Studio 中不是。在 VS 中,++s 和 --s 直到 printf 完成后才会生效。 【参考方案1】:

函数参数的求值顺序未指定。

来自 c99 标准:

6.5.2.2 函数调用

10/ 函数指示符的求值顺序,实际 参数,实际参数中的子表达式是 未指定,但在实际调用之前有一个序列点。

不过,这只是问题的一部分。另一件事(实际上更糟,因为它涉及未定义的行为)是:

6.5 表达式

2/ 在前一个和下一个序列点之间,一个对象应该有 它的存储值最多修改一次由评估 表达。此外,先验值应仅读取到 确定要存储的值。

在我们的例子中,所有参数评估仅在 2 个序列点之间:前一个 ; 和进入函数之前但在所有参数都被评估之后的点。你最好不要写这样的代码。

C 标准在某些地方相当宽松,为编译器可能进行的优化留出了空间。

【讨论】:

您可能应该添加一个未定义的原因(优化)【参考方案2】:

传递给函数的参数的顺序在标准中没有定义,由编译器使用的calling convention 决定。 我认为在您的情况下,cdecl 调用约定(许多 C 编译器用于 x86 架构)用于从右到左评估函数中的参数。

【讨论】:

这也应该提到代码有未定义的行为。快速浏览此 Q/A 而不修改其他答案的人可能会忽略这一事实,并认为问题中的行为对于 cdecl 调用是可靠的。 问题是关于求值顺序未指定),而不是关于如何传递参数(在求值之后)。【参考方案3】:

这个函数调用是未定义的行为:

printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);

在两个序列点之间多次修改对象是 C 中未定义的行为。

这也是未定义的行为,因为您有 6 个转换规范,但格式只有 5 个参数。

【讨论】:

由于注释长度有限,我将语句改写为 printf("%d %d %d %d",i,++i, i++,i); with i=1 在评估期间,首先它将从右开始的所有值放入堆栈。如果变量有任何后/前增量,它会评估并存储该值。否则,它将作为变量存储在堆栈中并获取 var 的最终值。最右边的 i - i 在堆栈中,对于 i++ - 1,因为它的 post inc 将 i 更新为 2。对于 ++i - 3,pre inc 并将 i 更新为 3,因为 i 在堆栈中。 for var as i in stack 将 i 的最终值设为 3。最终输出将为 3 3 1 3 @Dinesh 感谢您的反对,但正如其他人已经告诉您的那样,您错了。 C 标准中没有“堆栈”,但有一个具有相关要求的序列点的概念。【参考方案4】:

两点:

函数参数以未指定的顺序进行评估。这允许编译器根据自己的喜好进行优化。 您的特定参数会调用未定义的行为。不允许在序列点之前多次修改i

【讨论】:

您不能在一个语句中多次修改 i。 这不是真的:例如:i++, i++; 是一个语句,而您正在修改一个对象两次,但不是 UB。 这个更好的术语是什么?我觉得表达也不合适。我已经切换到序列点,但我现在不太喜欢这个措辞。 sequence point 是正确的措辞。【参考方案5】:

printf 参数的评估顺序未指定。除其他外,这取决于您使用的系统的调用约定。此外,这也是一种未定义的行为,因为您在没有任何序列点的情况下多次修改i。顺便说一句,缺少一个参数。

【讨论】:

调用顺序不是未指定的。它通过从右侧开始推送元素来遵循堆栈的顺序。 @Dinesh:根据 C 标准,你错了。

以上是关于解释 printf 中的评估顺序 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

OCaml和OCaml评估模型中的功能应用列表

Java中的条件评估过程[重复]

Javascript对象初始化和评估顺序[重复]

记住C中运算符的评估顺序和优先级的快捷方式[重复]

评估布尔语句的顺序是啥? [复制]

Java中评估顺序的规则是啥?