我注意到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;
}
或类似的东西,显然更复杂。
答案 0 :(得分:16)
这是预期的。优化会导致特定的代码分析运行,这就是gcc如何找到未初始化的变量。它在手册页中:
。 。 。这些警告取决于优化
答案 1 :(得分:3)
这实际上与gcc非常相似。是的,这是可以预期的。
据我了解,为了优化,编译器会生成大量度量并以允许检测未初始化或未使用的方式转换代码(或者更准确地说,它具有代码的表示)例子的变量(还有一些其他警告,我不记得列表)。
在没有优化的情况下做同样的事情需要做,然后废弃所有这些分析。这会显着减慢编译速度,因为没有好处(特别是在调试中,编译器不会重新安排代码)。
答案 2 :(得分:3)
优化器执行的代码流分析允许它检测正常(和更快)编译无法检测的潜在问题。问题始终存在,编译器只是没有检查它。
即使发出此警告,由于实际使用该功能,实际上也可能不是问题;编译器将假定其参数类型的所有可能值(以及函数中使用的任何外部变量)可能以所有可能的组合出现 - 导致至少一个使用该变量的路径而不分配值。您的实际使用将具有更多限制性的可能状态集,因此该路径可能永远不会在实践中发生。简单的解决方案就是初始化变量,如果只是为了关闭编译器 - 它将不需要任何费用。
我总是使用优化器作为穷人静态分析的一种形式,即使我最终不打算在生产代码中使用它。同样,出于同样的原因,我经常使用多个编译器。有些编译器执行其他编译器没有执行的检查,或者为相同的错误生成不同措辞的消息,这通常有助于解释一些更为钝的消息。
引用:
当-g时我更信任编译器 旗帜在
虽然如果编译器有错误,它可能是在优化器中(它是最复杂的部分),但对于像GCC这样的成熟编译器来说,这将是一个非常罕见的发现。相反,人们经常发现他们的工作代码在优化时会失败;通常,代码总是有缺陷的(可能它依赖于未定义或编译器定义的行为),并且优化器刚刚暴露了这个缺陷。所以我建议如果你发现你的代码在优化之下,在编译器之前怀疑代码 - 奥卡姆的Razor适用。
答案 3 :(得分:1)
我的编译器标志:
CFLAGS=-W -Wall\
-Wno-non-template-friend\
-Wold-style-cast\
-Wsign-promo\
-Wstrict-null-sentinel\
-Woverloaded-virtual
# -Weffc++
-Weffc ++可能真的很烦人,所以有时候我会尝试但是通常我会把它关掉。 试试这些 - 以及手册中的其他内容 - 让我们看看我们看到的内容。
答案 4 :(得分:1)
是的,这是明确定义的行为。当GCC的优化器未启用时,它不会执行某些类型的执行路径检查(以避免执行这些类型检查的性能损失)。某些情况,例如使用未初始化的变量,只有在执行这些额外检查时才能检测到。因此,对于-O0
,GCC无法警告这些情况。
答案 5 :(得分:1)
编译器可以将事物移动到优化的事实可能导致问题并导致不确定的行为(如下面的手册所述);我认为看到代码尝试并帮助理解是有帮助的。
优化代码采用的快捷方式 可能偶尔会产生令人惊讶的 结果:您声明了一些变量 根本不存在;控制流程 可能会暂时移动到你没有的地方 期待它;有些陈述可能不是 执行因为他们计算常量 结果或它们的价值已经存在 在眼前;某些陈述可能会执行 在不同的地方,因为他们是 走出了循环。
答案 6 :(得分:0)
我在msvc 6编译器中遇到了同样的问题。初始化有问题的变量,从编译器角度消除了错误路径的可能性。