【问题标题】:Explain the order of evaluation in printf [duplicate]解释 printf 中的评估顺序 [重复]
【发布时间】: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 完成后才会生效。

标签: c 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 标准,你错了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 1970-01-01
  • 2019-02-06
  • 2012-12-05
  • 2016-12-22
  • 2015-04-07
相关资源
最近更新 更多