我的 GCC 7.3.0 和 8.2.0 有一些我无法解释的奇怪行为。
这个程序显然以分段错误结束:
int main()
{
double array[2]={0, 0};
printf("%f\n", array[999]);
return 0;
}
编译为
gcc -Wall -O2 main.c
产生警告
main.c: In function 'main':
main.c:6:5: warning: 'array[999]' is used uninitialized in this function [-Wuninitialized]
printf("%f\n", array[999]);
^~~~~~~~~~~~~~~~~~~~~~~~~~
但关闭优化后:
gcc -Wall main.c
它根本不产生任何警告。
我的代码 linter 和调试编译 (gcc -g) 使用 -O0 并且没有发现我犯的类似越界错误,直到我将其编译为打开优化的发布。在 linter 中设置 -O1 按预期发布警告。
这是 GCC 中长期存在的、有记录的限制。引用GCC 3.0 手册 https://gcc.gnu.org/onlinedocs/gcc-3.0.4/gcc_3.html#IDX165:
-Wuninitialized
如果在未初始化的情况下使用自动变量,或者变量可能被变量破坏,则发出警告setjmp
call.
这些警告仅在优化编译时才可能出现,因为它们需要仅在优化时计算的数据流信息。如果你不指定-O
,您根本不会收到这些警告。
The 当前版本的手册 https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Warning-Options.html#index-Wuninitialized实际上删除了该引用的第二段,而是说“因为这些警告取决于优化,因此存在警告的确切变量或元素取决于精确的优化选项和所使用的 GCC 版本。”这是因为,在 GCC 3.0(2001 年发布)和 GCC 8.2(2018 年发布)之间的某个时刻,编译器得到了改进,因此will在不优化时至少对未初始化变量的某些使用发出警告。例如,简单的测试
int foo(void) { int x; return x; }
当使用 GCC 8.2 进行编译时,确实会引发警告-O0 -Wall
.
值得指出的是perfect未初始化变量的诊断简化为臭名昭著的停机问题 https://en.wikipedia.org/wiki/Halting_problem——这意味着这是不可能完成的。您可以实现一组保守正确的规则(它们将检测未初始化变量的所有使用,但它们可能会声称某些变量在未初始化的情况下使用),例如爪哇的明确的分配 https://docs.oracle.com/javase/specs/jls/se7/html/jls-16.html规则,但这种方法历来在 C 程序员中并不受欢迎。考虑到在不优化时需要最少的误报以及快速编译的需求,GCC 在优化时进行更详细分析的方法是可以理解的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)