15

我在使用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;
}

我有点卡住了,正在考虑这是一个编译器错误。有什么想法吗?

4

2 回答 2

18

事实上,这是 gcc 中的一个已知问题。
gcc 因报告不正确的未初始化变量而臭名昭著。
缺点已被适当指出,并且有一个克服缺点的主动性:
更好的未初始化警告

GNU Compiler Collection 警告使用带有选项的未初始化变量-Wuninitialized。然而,当前的实现有一些明显的缺点。一方面,一些用户想要更详细和一致的警告。另一方面,一些用户希望得到尽可能少的警告。该项目的目标是实现这两种可能性,同时提高当前的能力。

该计划旨在提供更好的警告,并引用了与您的案例类似的示例案例。相关部分是:

对于特定用户,用户理解为误报的内容可能不同。一些用户对由于优化器的操作与当前环境相结合而隐藏的案例感兴趣。但是,许多用户不是,因为这种情况是隐藏的,因为它不会出现在编译的代码中。典型的例子是

int x;
if (f ())
     x = 3;
return x;

其中 'f' 对于当前环境总是返回非零值,因此,它可能会被优化掉。在这里,一组用户希望得到一个未初始化的警告,因为 'f' 在别处编译时可能返回零。然而,其他用户组会认为虚假警告是关于正在编译的可执行文件中不会出现的情况。

于 2013-01-03T04:06:31.963 回答
1

不知道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没了。

于 2020-12-24T20:54:40.850 回答