如何让gcc警告我关于"int i = i;"的问题

29

一个简单的程序:

int main()
{
    long i = i;

    return 0;
}

以 C 编译没有错误和警告。

$ gcc -Wall -Wextra -pedantic 1.c

使用C++编译时会出现警告:

$ c++ -Wall -Wextra -pedantic 1.c
1.c: In functionint main()’:
1.c:3:7: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
  long i = i;

在这两种情况下,变量i似乎都是0,尽管在C++中它可能未初始化。我实际上在一个函数中犯了这样的笔误,找到它相当困难。我该怎么做才能避免这种情况?我希望至少能得到一个警告。此外,Clang在任何情况下(C或C++)都没有给出任何警告。是否有标准的特定部分说明了这种行为?

编辑:尝试过类似的事情:

$ cat 1.c
int main(void)
{
    int k = k + 0;
    int i = i + 1;
    return 0;
}

警告(在C语言中)仅针对“i”生成。

$ gcc -Wall -Wextra 1.c
1.c: In functionmain’:
1.c:4:6: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
  int i = i + 1;

2
C语言通常可以处理垃圾值,但这有点令人惊讶,尤其是在长期使用Python之后(我预计会出现NameError错误:). - Mad Physicist
2
警告是“实现质量”问题。标准对它们没有任何说明。 - Basile Starynkevitch
4
在C语言中,未初始化的变量含有垃圾数据,因此对这样的操作结果是不可预测的,即使该变量被用于语句的右侧运算也是如此。@KABoissonneault所说的情况仍然属于未定义行为。 - absoluteAquarian
3
“不可预测的数据”是一种未指定行为。未定义行为意味着实现可以做任何事情,没有任何限制。 - KABoissonneault
1
@Lundin 赋值 i = i 是一个无操作,但是 int i = i; 不是一个赋值,它意味着完全不同的事情。int i = i; 没有警告是非常有意义的,请参阅 GCC 文档中的 -Winit-self。自初始化是传统的 C 习惯用法,用于避免未初始化的警告,因此 GCC 默认不会发出警告。 - Jonathan Wakely
显示剩余12条评论
3个回答

19

要使用GCC编译C程序,您需要添加编译器标志-Winit-self。(您还需要-Wall-Wuninitialized,请参见下文。)对于GCC编译C++程序,该标志已被-Wall隐含,但对于C语言,需要显式指定; 它也不是-Wextra的一部分。

对于Clang,情况稍微有些有趣。在OP中的片段中,Clang不会产生任何诊断。 但是,使用GCC手册下面提供的略有不同的代码片段,将提供诊断:

int f() {
  int i = i;
  return i;
}
在上面的代码片段中,不同之处在于实际使用了未初始化的 i 值。显然,在原始代码中,Clang检测到变量是无用的,并在应用诊断之前将其作为死代码消除。 在Clang中,通过-Wuninitialized触发诊断,该选项与GCC中的-Wall一起启用。以下是来自GCC手册的摘录:-Winit-self (仅限C、C++、Objective-C和Objective-C++)

警告未初始化的变量被使用其自身进行初始化。 请注意,此选项只能与-Wuninitialized选项一起使用。例如,仅当指定了-Winit-self时,GCC才会警告以下代码片段中未初始化的i
        int f()
          {
            int i = i;
            return i;
          }

在C++中,-Wall启用了此警告。另外,在C和C++中都需要使用-Wuninitialized来实现-Wall的功能。但是,请注意,除非请求一些优化级别,否则许多未初始化的使用情况将不会被检测到。(据我所知,这不适用于-Winit-self。它可以在没有优化的情况下被检测到。)


令人烦恼的是,当您取消标记问题为重复时,先前标记的重复项将消失。我取消了标记,因为没有一个重复的问题实际上回答了正文中的问题;我还编辑了标题。

以下是原始的重复项,可能会有用:


1
使用编译器选项之前,你必须自己发现警告的意义是什么?gcc 的开发者有时候会做一些棘手的事情!:) - Luis Colorado

4

基本上,它是:

int i;
i = i;

其中i是未初始化的值。


4
C 和 C++ 从来都不是“安全语言”,对编译器进行扭曲以防止每种可能的人为错误几乎没有意义。这就是这些语言中 UB 存在的全部原因。 - StoryTeller - Unslander Monica
3
这怎么回答问题呢?有一行警告是“变量i可能未初始化使用”,编译器会显示这个警告。 - 463035818_is_not_a_number
3
@notnonuninvisible - 我没有说"坏",我说的是"不安全"。这并不是一回事。缺乏安全也意味着拥有力量,因为没有任何安全保障会妨碍你,而你又不需要它们。很抱歉,但讨论这个哲学观点是离题的。唯一与主题相关的问题已在重复问题中得到回答,我认为我选择得当。 - StoryTeller - Unslander Monica
2
这个讨论已经偏离主题了。应该在聊天室中继续。 - François Andrieux
1
这个回答似乎没有回答问题,问题是:“如何让gcc警告我关于'int i=i;'” - Jeremy Friesner
显示剩余10条评论

4
组合使用 -Wall -Winit-self 似乎会增加此诊断:
$ gcc -Wall      -Winit-self t.c
t.c: In functionmain’:
t.c:3:10: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
     long i = i;
          ^

具体来说,它是通过-Wuninitialized -Winit-self实现的(前者由-Wall启用) - Jonathan Wakely

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