我的GCC 7.3.0和8.2.0有一些我无法解释的奇怪行为。 该程序显然以Segmentation错误结束:
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和Debug编译(gcc -g)使用-O0,并且没有遇到类似的超出范围的错误,直到我将其编译为“打开并启用优化”。在linter中设置-O1会按预期发布警告。
答案 0 :(得分:4)
这是GCC中长期存在的记录限制。引用manual for GCC 3.0:
-Wuninitialized
警告是否使用了未先初始化的自动变量,或者是否可能被
setjmp
调用破坏了。这些警告仅在优化编译时才可能出现,因为它们需要仅在优化时才计算的数据流信息。如果未指定
-O
,则只会收到这些警告。
current version of the manual实际上删除了引号的第二段,而是说:“由于这些警告取决于优化,因此警告的确切变量或元素取决于精确的优化选项和所使用的GCC版本”。这是因为,在GCC 3.0(2001年发布)和GCC 8.2(2018年发布)之间的某个时刻,对编译器进行了改进,以便在不进行优化时,将至少对某些未初始化变量的使用给出警告。例如,琐碎的测试
int foo(void) { int x; return x; }
在使用-O0 -Wall
的GCC 8.2编译时会引发警告。
值得指出的是,对未初始化变量的 perfect 诊断可以减少到臭名昭著的Halting Problem,这意味着它无法完成。您可以实施一系列保守地正确的规则(它们将检测未初始化变量的所有使用,但它们可能会声称某些变量在未初始化时未使用),例如Java的definite assignment规则,但是这种方法历来在C程序员中并不受欢迎。考虑到需要最小的误报,但在不进行优化时也需要快速编译的要求,因此可以理解,GCC在优化启动时进行更精细分析的方法是可以理解的。