【问题标题】:Increment and decrements in C(gcc) compiler [duplicate]C(gcc)编译器中的增量和减量[重复]
【发布时间】:2013-08-12 16:31:06
【问题描述】:

谁能告诉我评估答案的正确程序(内部工作)?

#include<stdio.h>
main()
{
int a=10;
printf("%d %d %d\n",a,a++,++a);
return 0;
}

【问题讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读About 页面。您已经通过在序列点之间修改a 两次来调用未定义的行为,因此任何事情都可能发生并且很好。这个问题的小变种经常被问到;希望它很快就会作为副本关闭。

标签: c algorithm increment decrement


【解决方案1】:

此代码没有单一的正确行为。
从技术上讲,该程序的任何输出或结果都是正确的,即使是 nasal demons

属于undefined behavior

虽然我们可以猜测可能可能的结果,但在这种情况下,C 语言允许任何事情。

【讨论】:

  • 这个答案没有说明行为未定义的原因。
  • 请使用 gcc (gcc-4.8.1) 告诉。答案是 12 11 12 所以请告诉我流控制(使用堆栈或任何其他逻辑)
  • 即使我们这样做了,那个版本的 gcc 可以在调用 UB 时为所欲为;它甚至不必每次都做同样的事情。
  • @Aman 请阅读en.wikipedia.org/wiki/Undefined_behavior,尤其是“……不可预测……程序员无法预测会发生什么”。
【解决方案2】:

在表达式的单个部分1 内,不允许(在 C 定义的行为范围内)两次修改对象或修改对象并单独使用它的价值。

您的表达式printf("%d %d %d\n",a,a++,++a) 包含aa++++a。这是不允许的,因为a++++a 都修改了a。这也是不允许的,因为a使用aa++分别修改a

不要这样写代码。

当你这样做时,行为是不确定的。编译器可能会以任何顺序评估这三件事,或者它可能会“破坏”并做一些完全不同的事情。你可能得到“12 11 12”,因为编译器生成的代码是这样的:

  • 首先,记录a++ 的值 (11) 并计算增量值 (12),但将该值保存在临时寄存器中(暂时不要将其写入内存)。
  • 其次,记录++a的值(12,因为a仍然是11)。
  • 第三,更新a 的值,无论是从临时的还是从++a 或两者兼而有之。
  • 第四,记录a的值(现在是12)。
  • 第五,将这些值 12、11 和 12 传递给 printf

但代码可能做了其他事情。在这种情况下,您只能通过检查生成的汇编代码来判断。您无法从 C 标准所说的内容中分辨出来,因为 C 标准没有说明在这种情况下会发生什么。检查汇编代码只会告诉您在这种情况下会发生什么;当为不同的处理器架构编译相同的 C 源代码、使用不同的编译开关或更改编译器版本时,它可能会有所不同。


1表达式可以按顺序点分成多个部分。有关序列点的更多信息,请参阅this answer

【讨论】:

  • 不正确,您是被允许的,即使行为未定义。
  • @AlterMann:当然,你“被允许”编写完整的 gobbledygook 并将其提供给编译器。显然,您“被允许”做任何事情,但这里的上下文是在 C 标准定义的范围内不允许这样做。这个答案明确指出“当你这样做时,行为是未定义的”。对语言提出哲学或挑剔的主张是没有帮助的。重要的是要向学习者强调这是要避免的代码。
猜你喜欢
  • 2014-02-11
  • 2017-10-11
  • 2013-01-19
  • 1970-01-01
  • 2015-05-21
  • 2013-07-15
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
相关资源
最近更新 更多