c - GCC - 没有关于带有 -O0 的未初始化数组的警告
问题描述
我的 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 的手册:
-Wuninitialized
如果在没有首先初始化的情况下使用自动变量,或者变量可能被
setjmp
调用破坏,则发出警告。这些警告仅在优化编译时才可能出现,因为它们需要仅在优化时计算的数据流信息。如果您不指定
-O
,您根本不会收到这些警告。
当前版本的手册实际上已经删除了该引用的第二段,而是说“因为这些警告取决于优化,所以有警告的确切变量或元素取决于精确的优化选项和使用的 GCC 版本。” 这是因为,在 GCC 3.0(2001 年发布)和 GCC 8.2(2018 年发布)之间的某个时间点,编译器得到了改进,因此它会在未优化时至少对未初始化变量的某些使用发出警告。例如,琐碎的测试
int foo(void) { int x; return x; }
使用 GCC 8.2 编译时确实会引发警告-O0 -Wall
。
值得指出的是,对未初始化变量的完美诊断会归结为臭名昭著的停机问题——这意味着它无法完成。您可以实现一组保守正确的规则(它们会检测所有未初始化变量的使用,但他们可能会声称某些变量在未初始化时未初始化使用),例如 Java 的明确赋值规则,但这种方法在历史上一直是在 C 程序员中不受欢迎。考虑到在不优化时对最小误报以及快速编译的需求,GCC 在优化时进行更精细分析的方法是可以理解的。
推荐阅读
- javascript - 如何使用 UiPath 从 Google Chrome JavaScript 警报弹出窗口中提取数据
- javascript - 为什么动态生成的元素没有在悬停时显示?
- python - Azure Cosmos DB Python SDK:如何读取更改源?
- angular - 如何在Angular中使用管道格式化日期
- docker - Docker 如何修改现有镜像
- image - 使用垂直分隔符绘制两个图像
- mongodb - 外部字段是对象数组时的MongoDB查找
- javascript - 将 Json 文件读入变量
- php - 如何将 $bad = 数组条件添加到 die 函数?
- javascript - 在生产中调用销毁时,不会从 Mongo 存储中删除 Express 会话数据