在C语言中,一个(空)无限循环是未定义行为吗?

14

在C语言中,像for (;;);这样的无限循环是否属于未定义行为?(在C++中是这样的,但我不确定C语言是否也一样。)


2
另请参阅:编译器是否允许消除无限循环? - Shafik Yaghmour
2个回答

13
不,C语言中的 for (;;) 语句的行为是被定义明确的。 N1570,该文件与官方2011 ISO C标准基本相同,在第6.8.5段第6个自然段中指出:
一个迭代语句,其控制表达式不是常量表达式,其在其体、控制表达式或(对于for语句)其expression-3中执行没有输入/输出操作,不访问易失性对象,并且在其body、controlling expression或(在情况下)期间执行没有同步或原子操作,可以假定由实现终止。
这句话带有两个脚注:
省略的控制表达式将被替换为非零常量,即常量表达式。
这意在允许编译器进行转换,例如删除空循环,即使不能证明终止。
第一个脚注明确了for (;;)的控制表达式被视为具有常量控制表达式的处理方式。
规则的要点是当编译器不能证明循环是否终止时允许优化。但如果控制表达式是常量,则编译器可以轻松地证明循环是否终止,因此不需要额外的允许。

这个规则的目的是允许编译器在无法证明循环终止时进行优化。但是,如果控制表达式是常量,编译器可以轻松地证明循环是否终止。我同意这个观点,但是为什么在C++中while(1);会被视为未定义行为呢?难道不应该适用相同的推理吗? - user541686
@Mehrdad:在我看来应该可以,但是C++标准并没有将常量控制表达式排除在规则的版本之外。 - Keith Thompson
2
只是为了确保理解所有这些意思:在C语言中,您可以编写一个程序,其中逻辑完全由信号处理程序实现,并使程序处于无限循环状态以等待事件。这听起来不像是某种非常聪明的实现方式,但我同意语言不应该禁止这样做。在C++中,这将被禁止吗? - Jens Gustedt

0

针对C++的这个问题的原理与C无关。5.1.2.3p6节规定了优化的限制之一:

在程序终止时,写入文件的所有数据必须与根据抽象语义执行程序产生的结果相同。

现在问题变成了“根据抽象语义执行会产生什么数据?”假设一个信号中断了循环,程序可能会终止。然而,在此之前,抽象语义不会产生任何输出。如果有的话,编译器可能会优化掉puts("Hello");


澄清一下,考虑以下情况:一个仅包含空循环和 puts("Hello"); 的程序被编译并执行,使用 kill 发送信号让程序退出,程序通过从信号处理程序调用 exit 来优雅地退出。@Deduplicator,哪里有 UB?据我所知,信号中唯一的 UB 是如果程序从与计算错误对应的信号之一返回。然而,在这里不是这种情况,因为信号处理程序调用 exit,而不是返回。请确保你的事实准确无误。 - autistic
exit执行退出处理程序和其他一些事情,这些事情并不能保证完全正常工作。 - Deduplicator
@Deduplicator,你是在告诉我编译器可能无法优化掉puts("Hello");,因为其中一个atexit处理程序中可能存在未定义的行为吗?在atexit处理程序中出现未定义的行为的后果是...未定义的。这如何阻止此优化发生呢? - autistic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接