使用-Wall编译C语言代码时,未初始化的变量不会被警告提示。

4

我有一个例子程序存在缺陷,应该会出现一个关于未初始化变量的警告,但是当我使用gcc编译它时却没有出现任何警告。

下面是代码:

#include <stdio.h>

int main()
{
    int foo;

    printf("I am a number: %d \n", foo);

    return 0;
}

以下是我运行的命令:cc -Wall testcase.c -o testcase

但是我没有得到任何反馈。据我所知,这个命令应该会产生:

testcase.c: In function 'main': 
testcase.c:7: warning: 'foo' is used uninitialized in this function

在Zed Shaw的C语言教程中,出现了一个类似的例子,它似乎可以正确地警告Zed Shaw(请参阅类似示例)。这是我最初尝试的例子,我注意到它并没有按照预期工作。

有什么想法吗?

编辑:

gcc版本:

i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)

使用Clang,就这样搞定了 ;-) - rubenvb
rubenvb,结果证明这是有效的,将其发布为答案,我会接受它! - Nick Knowlson
4个回答

8

您是否开启了优化编译选项?以下是我的man gcc页面上的内容:

  -Wuninitialized
       Warn if an automatic variable is used without first being
       initialized or if a variable may be clobbered by a "setjmp" call.

      These warnings are possible only in optimizing compilation, because
       they require data flow information that is computed only when
       optimizing.  If you do not specify -O, you will not get these
       warnings. Instead, GCC will issue a warning about -Wuninitialized
       requiring -O.

我的gcc版本是:

i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)

实际上,我刚刚在gcc 4.4.5上尝试了一下,即使没有使用-O,我仍然会收到警告。因此,这取决于您的编译器版本。


感谢您的回答。我尝试了cc -Wall -O testcase.c -o testcasecc -Wuninitialized -O testcase.c -o testcase,但没有任何区别。此外,gcc并没有发出关于-Wuninitialized需要-O的警告。 - Nick Knowlson
@NickKnowlson:在gcc 4.2中,-Wall似乎不意味着-Wuninitialized。此外,该版本的gcc似乎无法检测到foo实际上未被使用。 - Greg Hewgill
文档上说得不一样,看起来是这样的。 "那个版本的gcc似乎无法检测到foo实际上未使用" 那么这就是真正的答案吗?由于某种原因,该版本无法检测到foo未初始化?我将尝试更多的情况,并查看是否可以创建任何条件,在那种情况下它可以检测到。 - Nick Knowlson

2

更新你的编译器。

$ cat test.c
#include <stdio.h>

int main(void)
{
    int foo;
    printf("I am a number: %d \n", foo);
    return 0;
}

$ gcc -Wall -o test ./test.c
./test.c: In function ‘main’:
./test.c:7:11: warning: ‘foo’ is used uninitialized in this function [-Wuninitialized]
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) 
$ 

4
我可以确认GCC 4.5.3、4.6.3和4.7.0都对此发出了警告。 - rubenvb
@rubenvb:你(可能)只能确认你的发行版在默认配置文件中有相当不错的设置,纯净的gcc甚至不会打开优化选项(-O,也不会使用--march=native、--mtune=native,没有graphite等任何东西)。如果你手动编译了gcc并且可以说出另外的情况,那么我向你道歉。 - Tomas Pruzina
他的问题可能是使用了苹果的分发版本包,LLVM前端也已经过时(被弃用),据我所知。 - Tomas Pruzina
1
事实上,我自己构建了GCC,并且没有更改默认配置文件(或CFLAGS环境变量,我在Windows上)@AoeAoe - rubenvb

0
编译器未必会在访问未初始化变量时发出警告,这是 C 标准未要求的。即使程序调用了未定义行为(假设没有语法错误和约束冲突),编译器也不必发出警告。
使用gcc,您可以使用-Wuninitialized为未初始化的变量启用警告。正如其他人所指出的那样,在最近版本的gcc中,当指定了-Wall时,-Wuninitialized会自动启用。

我很感激你的努力,但是我已经对这些都很熟悉了。 :) - Nick Knowlson
另外,我对此很好奇,当至少自版本2.95.3(2001年3月16日)以来指定了-Wall时,似乎已启用了-Wuninitialized。所以这并不是最近的事情了! :) http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_2.html#SEC8 - Nick Knowlson

0
使用Clang,问题就解决了。看起来是GCC的一个bug,因为Clang会像它应该做的那样发出警告。

更多信息:更新gcc也是一种选择,但使用clang对我来说是迄今为止更好的选择。 - Nick Knowlson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接