【问题标题】:What's the point of issuing a compiler warning for "while(true)" and not issuing one for "for(;;)"?为“while(true)”发出编译器警告而不为“for(;;)”发出编译器警告有什么意义?
【发布时间】:2011-03-10 10:04:43
【问题描述】:

当我使用带有“警告级别 4”的 Visual C++ 9 编译 C++ 代码时:

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

以及以下内容:

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

两者都会触发C4127: conditional expression is constant 警告,但以下情况:

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

编译没有警告。

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

【问题讨论】:

  • 因为第三个语句中没有任何条件表达式...而它在第二个和第三个语句中...。编译器如何在没有任何条件表达式的情况下生成有关条件表达式的警告?
  • 我通常使用#pragma warning 禁用C4127,尤其是在使用boost 时。

标签: c++ visual-c++ compiler-construction compiler-warnings


【解决方案1】:

警告用户使用常量条件表达式的原因是为了帮助避免表达式最终为常量的错误(例如,由于拼写错误)。在最后一种情况下,没有表达式,因此不会有意外成为常量的风险。

【讨论】:

    【解决方案2】:

    原因很简单,虽然很愚蠢。

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

    while(i >= 0) { --i; } // infinite if i unsigned
    
    while(SOME_MACRO(i)) // err, depends on the expansion of macros
    

    为重言式测试产生警告是编译器的一个重要功能,即测试结果要么总是真要么总是假,因为当它来自宏扩展或在依赖上下文。

    似乎 VC++ 在这里推得太远了,而不是考虑重言式条件,它可以找到所有 truefalse 条件的警告,即使它们已经在代码中明确说明。

    【讨论】:

      【解决方案3】:

      for ( ;; ) 构造是有意编写“无限”循环的规范方法。我可以想象编译器设计者不想为此生成警告。

      【讨论】:

      • 我想说因果关系是另一种方式 - 它是规范的因为它不会对某个流行的编译器系列发出警告。
      • 如果您包含 VS 以外的编译器,我认为它甚至不规范。我认为 gcc 不会对此发出警告?
      • @jk:您实际上是对的,GCC 不会对这些结构中的任何一个发出警告。我没有对此进行测试,只是推测。
      【解决方案4】:

      没有意义。毕竟,语言规范说 ($6.5.3/2),

      条件和条件中的一个或两个 表达式可以省略。 一个 缺失条件使得隐含 while 子句相当于 而(真)。

      所以即使根据标准,for ( ; ; ) 也等同于 while(true)。因此,我看不出为什么编译器应该在一种情况下发出警告而在另一种情况下不发出警告!

      --

      如果编译器决定发出警告,那么在我看来,编译器应该在条件为 missing 而不是存在时发出警告,以便将警告解释为 提示让程序员意图清楚地明确地提及。

      我的意思是,for ( ;; )for ( ;true; )明确 提及条件的情况更可能是错字。后者告诉程序员清晰明确的意图。正如 史蒂夫 在评论中所说:

      对于一个 int 值 y,char x = y 是 等价于 char x = (char)y,但是 你可能想要一个警告 隐式缩小转换 第一个但不是第二个。

      所以明确的意图不应该收到警告,而隐含的意图应该收到!

      【讨论】:

      • 不是我的反对意见,但我认为等价是一个红鲱鱼。再举一个例子,根据标准if (x = y) 等同于if ((x = y)),但GCC 警告前者而不是后者。对于 int 值 y,char x = y 等价于 char x = (char)y,但您可能需要对第一个而不是第二个的隐式缩小转换发出警告。
      • true 但我发现 while(true) 很可能是一个错字的想法令人信服。恕我直言 VS 在这里过于挑剔
      • @jk:我当然同意while(true) 不太可能是错字。事实上我更喜欢它,所以 MSVC 惹恼了我。它可能是预处理器扩展while(CONDITION) 的结果,而不是拼写错误,其中 CONDITION 被意外地定义为始终为真的东西。至少,当他们发明警告时,我一直认为这就是 MS 的想法。 IMO 仅当循环中也没有 break 时才应发出警告。或者根本没有——一旦你运行代码,意外的无限循环往往不是最微妙的错误......
      • @Steve:我在帖子中引用了您的评论。希望你不要介意。 :-)
      • @Steve: undecidable...如果您的循环被异常中断,编译器无法知道这一点,除非它检查函数调用的主体...这显然在另一个翻译单元中。
      【解决方案5】:

      编译器警告可帮助捕捉潜在的错误。在 while 循环中使用 always true 条件可能是一个错误。例如,在下面的代码中,这可能是一个错误,我希望编译器警告我:

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

      在这种情况下,在优化构建中,编译器可能会推断出条件始终为真(因为无符号整数不能小于 0)。因此需要在while 循环中检测始终true 条件。我认为编写检测此类错误的人并没有特例 while (true) 案例,因为有一种简单的方法可以使用 for (;;) 进行无限循环。

      您可以阅读here,如何决定是否在 Visual Studio 中添加警告(示例是关于 C#,但我认为团队在 @987654330 中对警告有相同的经验法则@)。

      【讨论】:

        猜你喜欢
        • 2011-01-28
        • 1970-01-01
        • 2017-02-13
        • 2019-12-18
        • 1970-01-01
        • 1970-01-01
        • 2019-11-23
        • 1970-01-01
        相关资源
        最近更新 更多