我正在阅读一本书中的一些代码,当我决定在sec
语句之前进行更改以查看while
的未初始化值:
#include<stdio.h>
#define S_TO_M 60
int main(void)
{
int sec,min,left;
printf("This program converts seconds to minutes and ");
printf("seconds. \n");
printf("Just enter the number of seconds. \n");
printf("Enter 0 to end the program. \n");
printf("sec = %d\n",sec);
while(sec > 0)
{
scanf("%d",&sec);
min = sec/S_TO_M;
left = sec % S_TO_M;
printf("%d sec is %d min, %d sec. \n",sec,min,left);
printf("Next input?\n");
}
printf("Bye!\n");
return 0;
}
这在GCC下编译时没有任何警告,即使此时sec
未初始化,我得到的值为32767
:
$ gcc -Wall test.c
$ ./a.out
This program converts seconds to minutes and seconds.
Just enter the number of seconds.
Enter 0 to end the program.
sec = 32767
但是当我评论while
声明时:
#include<stdio.h>
#define S_TO_M 60
int main(void)
{
int sec;
//min,left;
printf("This program converts seconds to minutes and ");
printf("seconds. \n");
printf("Just enter the number of seconds. \n");
printf("Enter 0 to end the program. \n");
printf("sec = %d\n",sec);
/*
while(sec > 0)
{
scanf("%d",&sec);
min = sec/S_TO_M;
left = sec % S_TO_M;
printf("%d sec is %d min, %d sec. \n",sec,min,left);
printf("Next input?\n");
}
*/
printf("Bye!\n");
return 0;
}
现在GCC发出警告,sec
最终为零:
$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:12:8: warning: ‘sec’ is used uninitialized in this function[-Wuninitialized]
printf("sec = %d\n",sec);
^
$ ./a.out
This program converts seconds to mintutes and seconds.
Just enter the number of seconds.
Enter 0 to end the program.
sec = 0
Bye!
为什么警告第二次显示但不是第一次显示?
答案 0 :(得分:8)
显然gcc
有一个长期存在的错误否定问题,此选项请参阅此错误报告:Bug 18501 - [4.8/4.9/5 Regression] Missing 'used uninitialized' warning (CCP) 以及重复的长列表:
重复:30542 30575 30856 33327 36814 37148 38945 39113 40469 42724 42884 45493 46684 46853 47623 48414 48643 49971 56972 57629 58323 58890 59225 60444
从最后的评论中注意到,我们可以看到这已经持续了十多年了:
嘿伙计们,今年将是这个bug的10周年纪念日。我们应该点蛋糕!
注意,如果你删除:
scanf("%d",&sec);
你也会收到警告,Marc Glisse也指出删除前四个printf
同样有用( see it live )。我没有在重复项中看到类似的示例,但不确定是否可以为此添加另一个错误报告。
另见Better Uninitialized Warnings说:
GCC能够警告用户使用未初始化变量的值。这样的值是未定义的,它永远不会有用。它甚至不能用作随机值,因为它很少是随机值。不幸的是,在一般情况下,检测何时使用未初始化的变量等同于解决停止问题。 GCC尝试使用优化器收集的信息检测某些实例,并在命令行中给出-Wuninitialized选项时对其进行警告。目前的实施存在许多缺点。首先,它仅在通过-O1,-O2或-O3启用优化时有效。其次,误报或否定的集合根据启用的优化而变化。这也会导致在发布之间添加或修改优化时报告的警告的高度可变性。
附注,clang
似乎很好地抓住了这个案例( see live example ):
warning: variable 'sec' is uninitialized when used here [-Wuninitialized]
printf("sec = %d\n",sec);
^~~
正如我在下面的评论中指出的那样,至少这个案例似乎已在gcc 5.0
修复。
答案 1 :(得分:5)
这一行:
scanf("%d",&sec);
GCC知道您在函数中初始化sec
某处。
作为一个单独的步骤,GCC可以进行流量分析,以确定在使用之前是否初始化sec
。遗憾的是,GCC并不总能进行您想要的流量分析,甚至根本不进行流量分析。有时流量分析是在其他信息不可用的阶段完成的。所以,你不能指望GCC搞清楚。
其他编译器会弄明白。例如,
~ $ clang-3.7 -c -Wall -Wextra -O2 ex.c ex.c:11:25: warning: variable 'sec' is uninitialized when used here [-Wuninitialized] printf("sec = %d\n",sec); ^~~ ex.c:5:12: note: initialize the variable 'sec' to silence this warning int sec,min,left; ^ = 0 1 warning generated.
GCC在检测到这些错误方面非常糟糕。