我正在使用警告级别为 -Wall -Wextra
的 g++并将警告视为错误 ( -Werror
)。
现在我有时会收到错误消息“变量 可能在此函数中未初始化地使用”。
“有时”是指我有两个独立的编译单元,它们都包含相同的头文件。一个编译单元编译没有错误,另一个给出上述错误。
头文件中的相关代码如下。由于函数很长,我只复制了下面的相关部分。
准确的错误是:
'cmpres' may be used uninitialized in this function
我用 *
标记了错误行下面。
for (; ;) {
int cmpres; // *
while (b <= c and (cmpres = cmp(b, pivot)) <= 0) {
if (cmpres == 0)
::std::iter_swap(a++, b);
++b;
}
while (c >= b and (cmpres = cmp(c, pivot)) >= 0) {
if (cmpres == 0)
::std::iter_swap(d--, c);
--c;
}
if (b > c) break;
::std::iter_swap(b++, c--);
}
( cmp
是一个仿函数,它接受两个指针 x
和 y
,如果 *x < *y
、*x == *y
或 *x > *y
分别返回 –1、0 或 +1。其他变量是指向同一个数组。)
这段代码是一个更大函数的一部分,但是变量 cmpres
没有在其他地方使用。因此我不明白为什么会生成此警告。此外,编译器显然理解 cmpres
永远不会被读取为未初始化的(或者至少,它并不总是警告,见上文)。
现在我有两个问题:
为什么不一致的行为?这个警告是由启发式生成的吗? (这是有道理的,因为发出此警告需要进行控制流分析,这在一般情况下是 NP 困难的,并且不能总是执行。)
为什么会出现警告?我的代码不安全吗?我开始欣赏这个特别的警告,因为它使我免于在其他情况下很难检测到错误 - 所以这个是一个有效的警告,至少有时是这样。在这里有效吗?
最佳答案
诊断未初始化变量且没有漏报或漏报的算法必须(作为子例程)包含解决 Halting Problem 问题的算法。 .这意味着没有这样的算法。计算机 不可能 100% 地做到这一点。
我不知道 GCC 的未初始化变量分析究竟是如何工作的,但我知道它对早期优化过程对代码所做的事情非常敏感。所以我一点也不惊讶你只是有时会得到误报。它确实区分了确定的情况和不能确定的情况 --
int foo() { int a; return a; }
产生“警告:‘a’是在此函数中使用未初始化”(强调我的)。
编辑:我发现一个案例,最新版本的 GCC(4.3 及更高版本)无法诊断未初始化的变量:
int foo(int x)
{
int a;
return x ? a : 0;
}
早期的优化注意到,如果 x
不为零,则函数的行为未定义,因此它们假设 x
必须为零 并替换整个带有“return 0;
”的函数主体 这发生在生成使用未初始化警告的传递之前,因此没有诊断。参见 GCC bug 18501血淋淋的细节。
我提出这个问题的部分原因是为了证明生产级编译器可能会以两种方式错误地诊断未初始化变量,部分原因是这是一个很好的例子,说明未定义的行为可以在执行时向后传播。测试 x
没有任何未定义的内容,但是由于依赖于 x
的代码控制具有未定义的行为,允许编译器假定控制依赖性永远不会满足并丢弃测试.
关于c++ - g++ 编译器中的 “Uninitialized use” 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4913254/