g++编译器:优化标志添加警告信息

6
我注意到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

where

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

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

4
请张贴导致警告的代码。 - anon
已更新包含一个具体示例。 - ldog
1
假设x是全局变量,任何访问x的操作都可能在它被赋值之前执行。你要么将示例简化得太过了,要么需要进行的分析超出了优化器的范围和能力。警告只是优化的副作用,它有机会警告你,所以就这样做了。 - Clifford
7个回答

18

1
+1 for the manual link; explains it all. 这也许是你的答案比我短得多的原因 ;) - Clifford

3

这在gcc中非常普遍,而且这是可以预料的。

据我理解,为了进行优化,编译器会生成大量的度量标准并转换代码(或者更准确地说是代码的表示方式),以便检测未初始化或未使用的变量等问题(还有一些其他警告,我不记得清单了)。

如果没有进行优化,做同样的事情就需要进行所有这些分析,然后将其舍弃。这将使编译显著变慢,而且没有任何好处(特别是在调试时,编译器不应该重新排列代码)。


3
优化器执行的代码流分析使其能够检测到正常(和更快)编译无法检测到的潜在问题。问题一直存在,只是编译器没有检查它。
即使发出了此警告,实际上可能并不是问题,这是由于函数在实践中的实际用途; 编译器将假定其参数类型的所有可能值(以及函数内使用的任何外部变量)都可能以所有可能的组合出现 - 导致至少有一条路径其中变量在使用时未被分配值。您的实际使用将具有更为严格的可能状态集,因此该路径在实践中可能永远不会发生。简单的解决方案只是初始化变量,即使只是为了让编译器保持安静-这将不花费您任何东西。
我总是将优化器用作贫穷人的静态分析形式,即使最终我并不打算在生产代码中使用它。同样,我经常为同样的原因使用多个编译器。某些编译器执行其他编译器不执行的检查,或者它们为相同错误生成不同措辞的消息,这通常有助于解释一些更为晦涩的消息。
引用:
“当-g标志打开时,我更信任编译器”
虽然确实如此,如果编译器存在错误,则很可能在优化器中(它是最复杂的部分),但对于成熟的编译器(如GCC),这将是非常罕见的发现。相反,人们经常发现他们的工作代码在进行优化时失败; 最常见的情况是代码始终有缺陷(可能依赖未定义或编译器定义的行为),而优化器只是暴露了该缺陷。因此,我建议如果您发现您的代码在优化下崩溃,请怀疑代码而不是编译器-奥卡姆剃刀适用。

+1 我发现尝试使用不同的编译器可以为您的代码提供有趣的视角,并且可以引起您已经做出但在其他地方可能无法保持的隐含假设的注意。这通常被忽视了。 - asveikau

1

我的编译器标志:

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

-Weffc++ 可能会非常烦人,所以有时我会尝试它,但通常我会将其关闭。 尝试这些 - 以及手册中的其他内容 - 让我们看看我们能发现什么。


1

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


1

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

优化代码采取的捷径有时会产生令人惊讶的结果:您声明的某些变量根本不存在;控制流可能会短暂地移动到您意料之外的位置;某些语句可能不会执行,因为它们计算出常量结果或其值已经在手头;某些语句可能会在不同的位置执行,因为它们已经移出了循环。


这与事物是否被移动无关。当禁用优化时,编译器甚至不执行可能检测未初始化变量的分析。优化永远不会导致变量未初始化。 - Rob Kennedy

0
在我的msvc 6编译器中遇到了同样的问题。在问题变量中进行初始化可以从编译器的角度消除路径错误的可能性。

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