我在使用gcc-4.7 (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
时遇到了一个非常奇怪的问题。我没有警告就无法编译以下有效代码:
extern void dostuff(void);
int test(int arg1, int arg2)
{
int ret;
if (arg1) ret = arg2 ? 1 : 2;
dostuff();
if (arg1) return ret;
return 0;
}
编译选项和输出:
$ gcc-4.7 -o test.o -c -Os test.c -Wall
test.c: In function ‘test’:
test.c:5:6: warning: ‘ret’ may be used uninitialized in this function [-Wmaybe-uninitialized]
但是,以下代码编译时没有警告(虽然组装效率稍低):
extern void dostuff(void);
int test(int arg1, int arg2)
{
int ret;
if (arg1 && arg2) ret = 1;
if (arg1 && !arg2) ret = 2;
dostuff();
if (arg1) return ret;
return 0;
}
我有些困惑,我认为这是一个编译器错误。有什么想法吗?
答案 0 :(得分:17)
确实这是gcc中的一个已知问题
gcc因举报 incorrect uninitialized variables 而臭名昭着
这些缺点已得到适当注意,并且有一项克服缺点的倡议:
的 Better Uninitialized Warnings 强>
GNU编译器集合警告使用选项
-Wuninitialized
使用未初始化的变量。但是,目前的实施有一些明显的缺点。一方面,一些用户想要更详细和一致的警告。另一方面,一些用户希望获得尽可能少的警告。该项目的目标是实现两种可能性,同时提高当前的能力。
该计划旨在提供更好的警告,并引用与您的案例类似的示例案例。相关部分是:
用户理解为误报可能对特定用户而言是不同的。一些用户对由于优化器的操作与当前环境相结合而隐藏的情况感兴趣。但是,许多用户不是,因为这种情况是隐藏的,因为它不会出现在编译的代码中。规范的例子是
int x;
if (f ())
x = 3;
return x;
其中'f'总是为当前环境返回非零,因此,它可以被优化掉。在这里,一组用户希望获得未初始化的警告,因为“f”在其他地方编译时可能返回零。然而,其他一组用户会考虑对正在编译的可执行文件中不会出现的情况发出虚假警告。
答案 1 :(得分:0)
不确定 gcc
在此期间是否已修复。如果没有,您可能想尝试clang
。恕我直言,它是更好的编译器,它可以进行更好的代码分析。
仅仅因为一些评论声称编译器是正确的,ret
可能会在未初始化的情况下使用,这是相反的证明。代码
int test(int arg1, int arg2)
{
int ret;
if (arg1) ret = arg2 ? 1 : 2;
dostuff();
if (arg1) return ret;
return 0;
}
只需将两个相同的 if
语句合并为一个即可轻松转换为以下代码:
int test(int arg1, int arg2)
{
if (arg1) {
int ret = arg2 ? 1 : 2;
dostuff();
return ret;
}
dostuff();
return 0;
}
这是等效的代码,现在应该很明显,ret
永远不能在未初始化的情况下使用。编译器错误,警告毫无意义。
但话说回来,代码可以进一步简化:
int test(int arg1, int arg2)
{
dostuff();
return (arg1 ? (arg2 ? 1 : 2) : 0);
}
问题解决了,ret
不见了。