【问题标题】:g++ compiler: optimization flag adds warning messageg++ 编译器:优化标志添加警告消息
【发布时间】:2010-01-27 08:29:55
【问题描述】:

我注意到 g++ 编译器的这种有趣行为,如果我在编译器中添加 -O3 标志,我会得到

otsu.cpp:220: warning: ‘x’ may be used uninitialized in this function

但是,当我不使用优化而是使用调试标志 -g 时,我根本没有收到任何警告。现在,当 -g 标志打开时,我更信任编译器;但是,我想知道这是否是应该预期的明确定义的行为?

为了清楚起见,导致这种情况的代码大致如下:

int x; //uninitialized


getAValueForX( &x ); // function makes use of x,
                     // but x is unitialized

在哪里

 void getAValueForX( int *x )
 {
     *x = 4;
 }

或者类似的东西,显然更复杂。

【问题讨论】:

  • 发布导致警告的代码
  • ok 更新了一个具体的例子。
  • 由于 x 是全局的,任何访问 x 的东西都可以在它被赋值之前这样做。要么你把这个例子简化得太多了,要么证明它不会超出优化器的范围和能力所需的分析。警告只是优化的副作用,它有机会警告你这样做。

标签: c++ optimization g++ warnings


【解决方案1】:

这是意料之中的。优化会导致特定的代码分析运行,这就是 gcc 查找未初始化变量的方式。它在手册页中:

。 . .这些警告取决于优化

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

【讨论】:

  • 手动链接+1;解释了这一切。这可能就是为什么你的答案比我的短得多;)
【解决方案2】:

这实际上在 gcc 中很常见。是的,这是意料之中的。

据我了解,为了进行优化,编译器会生成大量指标并转换代码(或者更准确地说,它对代码的表示)以允许检测未初始化或未使用的方式示例变量(还有一些其他类似的警告,我不记得列表了)。

在没有优化的情况下做同样的事情需要做,然后放弃所有这些分析。这会显着减慢编译速度(尤其是在调试中,编译器不应该重新排列代码)。

【讨论】:

    【解决方案3】:

    优化器执行的代码流分析允许它检测到正常(和更快)编译无法检测到的潜在问题。问题一直存在,只是编译器没有检查。

    即使发出此警告,由于实际使用该功能,实际上也可能不是问题;编译器将假定其参数类型的所有可能值(以及函数中使用的任何外部变量)可能以所有可能的组合出现 - 导致至少一个使用变量而不被分配值的路径。您的实际使用将有一组更严格的可能状态,因此该路径可能永远不会在实践中出现。简单的解决方案是初始化变量,如果只是为了关闭编译器 - 它不会花费您任何费用。

    我总是将优化器用作穷人静态分析的一种形式,即使我最终不打算在生产代码中使用它。同样,出于同样的原因,我经常使用多个编译器。一些编译器会执行其他编译器不执行的检查,或者它们会为相同的错误生成不同措辞的消息,这通常有助于他们解释一些更晦涩的消息。

    引用:

    当 -g 时我更信任编译器 标志开启

    虽然编译器确实存在错误,但它很可能在优化器中(这是最复杂的部分),但对于像 GCC 这样的成熟编译器来说,这将是一个非常罕见的发现。相反,人们经常发现他们的工作代码在优化时会失败;大多数情况下,代码总是存在缺陷(也许它依赖于未定义或编译器定义的行为),而优化器刚刚暴露了该缺陷。所以我建议如果你发现你的代码在优化下出现问题,怀疑编译器之前的代码 - 奥卡姆剃刀适用。

    【讨论】:

    • +1 我发现尝试各种编译器可以为您的代码提供有趣的视角,并提醒您注意您所做的可能在其他地方不成立的隐含假设。这常常被忽视。
    【解决方案4】:

    我的编译器标志:

    CFLAGS=-W -Wall\
     -Wno-non-template-friend\
     -Wold-style-cast\
     -Wsign-promo\
     -Wstrict-null-sentinel\
     -Woverloaded-virtual
    # -Weffc++
    

    -Weffc++ 真的很烦人,所以有时我会尝试它,但通常我会关闭它。 试试这些 - 以及手册中的其他内容 - 让我们看看我们看到了什么。

    【讨论】:

      【解决方案5】:

      是的,这是定义明确的行为。当 GCC 的优化器未启用时,它不会进行某些类型的执行路径检查(以避免进行此类检查的性能损失)。某些情况,例如使用未初始化的变量,只有在执行这些额外检查时才能检测到。因此,使用-O0,GCC 无法警告这些情况。

      【讨论】:

        【解决方案6】:

        编译器可以移动事物以进行优化的事实可能会导致问题并导致未定义的行为(如下面的手册所述);我认为查看代码以尝试帮助理解会很有帮助。

        优化代码所采用的快捷方式 可能偶尔会产生令人惊讶的 结果:您声明的一些变量 可能根本不存在;控制流 可能会短暂地移动到你没有移动的地方 期待它;有些陈述可能不是 执行,因为他们计算常数 结果或它们的值已经 在眼前;一些语句可能会执行 在不同的地方,因为他们是 移出循环。

        【讨论】:

        • 它与是否移动无关。在禁用优化的情况下,编译器甚至不会执行可以检测未初始化变量的分析。优化永远不会导致变量未初始化。
        【解决方案7】:

        我的 msvc 6 编译器也有同样的问题。初始化有问题的变量,从编译器的角度消除了错误路径的可能性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-02-12
          • 1970-01-01
          • 1970-01-01
          • 2017-11-06
          • 1970-01-01
          • 1970-01-01
          • 2012-03-10
          • 1970-01-01
          相关资源
          最近更新 更多