编译器是否允许消除无限循环?
优化编译器可以删除无限循环,这不会改变任何数据,就像
while(1)
/* noop */;
从分析数据流图编译器可以得出的那样,这样的循环是“死代码”,没有任何副作用。
C90/C99 标准是否禁止删除无限循环?
C90 或 C99 标准是否允许编译器删除此类循环?
更新:“Microsoft C 版本 6.0 本质上做了这种优化。”,请参阅 caf 的链接。
label: goto label;
return 0;
将转变为
return 0;
Can optimizing compiler delete infinite loops, which does not changes any data, like
while(1)
/* noop */;
From analyzing a data flow graph compiler can derive, that such loop is "dead code" without any side effects.
Is deleting of infinite loops prohibited by C90/C99 standards?
Does C90 or C99 standards permit compiler to deleting such loops?
Upd: "Microsoft C version 6.0 did essentially this optimization.", see link by caf.
label: goto label;
return 0;
will be transformed to
return 0;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
C11 澄清了这个问题的答案, C11 标准草案
6.8.5
Iteration statements 添加了以下段落:和脚注
157
说:所以你的具体例子:
对于优化来说不是公平的游戏,因为控制表达式是一个常量表达式。
无限循环作为 UB
那么为什么允许编译器优化无限循环(除了上面提供的例外),Hans Boehm 提供了使无限循环未定义行为的基本原理:N1528:为什么无限循环的未定义行为?,下面的引用给人一种很好的感觉问题涉及:
C99
由于 C99 没有这种划分,我们将参考
5.1.2.3
节中涵盖的as-if 规则,该规则基本上表示:编译器只需模拟程序的可观察行为,要求如下:严格阅读这一点似乎允许实现优化无限循环。我们当然可以想出优化无限循环会导致可观察行为发生变化的场景:
许多人会认为影响进程的终止也是可观察行为,这个立场是在 C 编译器反驳费马大定理:
更新
我不知何故错过了上述文章的后续内容,重新审视编译器和终止 其中关于
5.1.2.3
部分的内容如下:人们还可以提出一个较弱的论点,即需要在 C11 中创建一个允许删除空循环的内容意味着这不是允许的之前的优化。
这也适用于无限 goto 循环吗?
我相信其目的是这也适用于无限 goto 循环。在 C++ 中,情况显然如此,因为
1.10
[intro.multithread] 节说:然后,
N1528
中表达的意图是 C 和 C++ 标准同意:最后说:
目前,C11 标准在
5.1.2.4
部分中不包含类似的措辞多线程执行和数据竞争,但考虑到N1528
似乎明智的做法是假设编译器将无限 goto 循环视为 C 和 C++ 中的未定义行为。另请注意,请参阅此处的美国评论 38 和 N3196 这是对此进行了更改的纸张被应用。
C11 clarifies the answer to this question, in the draft C11 standard section
6.8.5
Iteration statements added the following paragraph:and footnote
157
says:So your specific example:
is not fair game for optimization since the controlling expression is a constant expression.
Infinite loops as UB
So why are compilers allowed to optimize away infinite loops with the exception provided above, well Hans Boehm provides a rationale for making infinite loops undefined behavior in: N1528: Why undefined behavior for infinite loops?, the following quote gives a good feeling for the issue involved:
C99
Since C99 does not have this carve out, we would look to the as-if rule covered in section
5.1.2.3
which basically says that the compiler only has to emulate the observable behavior of a program, the requirements are as follows:A strict reading of this would seem to allow an implementation to optimize an infinite loop away. We can certainly come up with scenarios where optimizing away an infinite loop would cause a change in observable behavior:
Many would argue that effecting the termination of a process is also observable behavior, this position is taken in C Compilers Disprove Fermat’s Last Theorem:
Update
I somehow missed the the follow-up to the above article, Compilers and Termination Revisited which says the following about section
5.1.2.3
:One could also make a weaker argument that the need to create a carve out in C11 to allow empty loop removal implies this was not an allowable optimization previously.
Does this apply to infinite goto loops as well?
I believe the intent is that this also applies to infinite goto loops as well. In C++ this is clearly the case since section
1.10
[intro.multithread] says:and then intent as expressed in
N1528
is that the C and C++ standard agree:and at the end says:
Currently the C11 standard does not contain the similar wording in section
5.1.2.4
Multi-threaded executions and data races but consideringN1528
it seems wise to assume compilers will treat infinite goto loops as undefined behavior in C and C++.Note also see US comment 38 here and N3196 which is the paper that this changed was applied from.
没有办法普遍检测无限循环:请参阅停止问题。因此,任何编译器能做的最好的事情就是进行适当的猜测 - 例如OP中提到的明显情况。
但为什么这是可取的呢?我可以看到发出警告并仍然允许该行为,但是删除循环并不是“优化” - 它改变了程序的行为!
There's no way to detect infinite loops universally: see the Halting Problem. So the best any compiler could do is take a decent guess - for example the obvious case mentioned in the OP.
But why would this be desirable? I could see emitting a warning and still allowing the behavior, but to remove the loop is not an "optimization" - it changes the behavior of the program!
循环不是死代码,它基本上阻止程序到达其后面的任何内容。如果删除循环,则不会发生这种情况,因此编译器无法删除循环。
它可能会将其替换为依赖于平台的空闲指令,以向处理器发出信号,表明该线程不再执行任何操作。
编译器可以做的是删除循环后面的所有代码,因为它无法访问并且永远不会被执行。
The loop is not dead code, it is basically preventing the program from ever reaching whatever comes after it. This is not what would happen if the loop was removed, so the compiler can not remove the loop.
It might replace it with a platform-dependent idle-instruction to signal the processor that the thread is not going to do anything any more.
What the compiler can do is remove any code that comes after the loop, because it is unreachable and will never be executed.
之前已经在
comp.lang.c
上讨论过很多次(例如此处)据我所知,没有任何共识结果。This has been discussed many times before on
comp.lang.c
(eg. here) without, as far as I know, any consensus outcome.它们是编写守护进程时必需的。为什么你想称它们为“死代码”?
They are a necessity when writing daemons. Why'd you want to call them dead code?
我相信较新的标准明确规定,如果一段代码不访问任何易失性变量、执行 I/O 等,则任何不依赖于第一段中计算的任何内容的其他代码都可以在其之前任意排序。如果无限循环不执行任何 I/O,也不计算程序稍后使用的任何值,则编译器可能会简单地推迟循环的执行,直到其他所有操作完成为止。
I believe that newer standards explicitly provide that if a piece of code does not access any volatile variables, perform I/O, etc. any other code which does not rely upon anything computed in the first piece may be arbitrarily sequenced before it. If an infinite loop does not perform any I/O, nor compute any value which is used later in the program, a compiler may simply defer execution of the loop until everything else has completed.