“while(true)”发出编译警告有什么意义,而“for(;;)”却没有发出警告?

10

当我使用Visual C++ 9编译C ++代码时,启用“警告级别4”,出现以下情况:

while( true ) {
   //loop body with break on certain condition
}

以及以下内容:

for( ; true; ) {
   //same loop body
}

两者都会触发C4127: conditional expression is constant警告,但以下代码不会:

for( ; ; ) {
   //same loop body
}

编译无警告。

为什么会有这种差异,特别是在第二和第三个变体之间?


1
因为第三个语句中没有任何条件表达式... 而第二个和第三个语句中都有... 编译器如何在没有任何条件表达式的情况下生成警告? - Mihir Mehta
1
我通常会使用 #pragma warning 禁用 C4127,特别是在使用 boost 时。 - Alexandre C.
相关:https://dev59.com/pUXRa4cB1Zd3GeqPs5Jp - CesarB
5个回答

10

警告用户常量条件表达式的原因是为了帮助避免由于笔误导致表达式最终成为常量而产生的错误。在最后一种情况下,没有表达式,因此没有意外成为常量的风险。


7

原因很简单,但很愚蠢。

诊断无限循环很重要,但有时并不明显:

while(i >= 0) { --i; } // infinite if i unsigned

while(SOME_MACRO(i)) // err, depends on the expansion of macros

编译器能够产生针对“同义测试”的警告是一个非常好的特性,这种测试要么总是为真,要么总是为假。因为当它来自于宏扩展或依赖上下文时,这并不明显。

但VC++似乎在这方面有些过分了,在已经在代码中明确表示为true或false的情况下,它仍然会发出警告。


4
< p > for ( ;; ) 结构是有意编写“无限循环”的规范方式。我可以想象编译器设计者不希望为此生成警告。


6
我认为因果关系是另一种方式 - 它是规范的,因为它在某个流行的编译器系列上不会发出警告。 - Steve Jessop
我认为如果你包括除了VS之外的编译器,它甚至不是规范的。我不认为gcc会对此发出警告? - jk.
@jk: 你说得没错,GCC确实不会对这两个结构进行警告。我并没有测试过这一点,只是推测而已。 - DevSolar

4
没有意义,毕竟语言规范($6.5.3/2)中写到,条件和表达式两者任意一个都可以省略。如果条件缺失,则隐含的while子句相当于while(true)。因此,即使按照标准来看,“for(;;)”与“while(true)”是等效的。因此,我不明白为什么编译器在一个情况下会发出警告,在另一个情况下却不会发出警告!
如果编译器决定发出警告,则我的观点是,编译器应该在条件缺失而不是存在时发出警告,这样警告就会被解释为提示程序员清楚明确地表达他的意图。
我的意思是,“for(;;)”更有可能是拼写错误,而不是明确声明条件的“for(;true;)”。后者清楚明确地告诉程序员的意图。正如Steve在评论中所说的那样:对于int值y,char x=y等同于char x=(char)y,但你可能希望针对第一个而不是第二个的隐式缩小转换发出警告。
因此,显式意图不应该接受警告,而隐式意图应该接受警告!

3
不是我投的反对票,但我认为等价性是一个转移注意力的话题。例如,根据标准,“if (x = y)”等价于“if ((x = y))”,但GCC会对前者而不是后者进行警告。对于int值y,“char x = y”等价于“char x = (char)y”,但你可能希望对第一个隐式缩小转换发出警告,而不是第二个。 - Steve Jessop
2
返回翻译的文本:true,但我认为while(true)可能是打字错误的想法不太令人信服。在我看来,VS在这里过于挑剔了。 - jk.
2
@jk:我完全同意while(true)不太可能是一个打字错误。事实上,我更喜欢它,所以MSVC让我很烦恼。它可能不是一个打字错误,而是预处理器扩展while(CONDITION)的结果,其中CONDITION被意外地定义为始终为真的某个值。至少,我一直认为这就是MS在发明警告时所考虑的。在我看来,只有在循环中也没有break语句时才应该发出警告。或者根本不发出警告——一旦运行代码,意外的无限循环往往不是最微妙的错误... - Steve Jessop
@Steve:我在我的帖子中引用了你的评论,希望你不介意。 :-) - Nawaz
@Steve:不可判定...如果您的循环被异常中断,编译器无法知道除非它检查函数调用的主体...这些显然在另一个翻译单元中。 - Matthieu M.
@Mattheiu:好的,但这只是更多理由警告代码调用TU。这将是一个比MS所做的更困难的分析。他们已经决定那些在循环条件下无法终止的循环值得警告,除了允许一种特定语法来抑制警告。所以我有一个抱怨,即他们选择的语法不是我喜欢的语法,另一个单独的抱怨是我认为警告本身就过度了。 - Steve Jessop

1

编译器警告有助于捕获潜在的错误。在 while 循环中使用一个始终为 true 的条件可能是一个错误。例如,在下面的代码中,这可能是一个 bug,我希望编译器能够对此发出警告:

unsigned int x;
// ...
while (x >= 0) {
    // ...
}

在这种情况下,在优化构建中,编译器可能会推断条件始终为真(因为无符号整数不能小于0)。因此需要检测while循环中始终为true的条件。我认为,谁写了这样一个错误的检测没有特别处理while(true)的情况,因为有一种简单的方法可以使用for (;;)进行无限循环。
您可以在这里阅读有关在Visual Studio中添加警告或不添加警告的决策的信息(示例是关于C#的,但我想团队对C++的警告有相同的经验法则)。

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