I was reading some code from a book, when I decided to make a change to see what the uninitialized value of sec
would be before the while
statement:
#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;
}
This compiles under GCC with no warnings, even though sec
is uninitialized at that point, and I get a value of 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
But when I comment out the while
statement:
#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;
}
Now GCC issues a warning and sec
ends up being zero:
$ 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!
Why did the warning show up the second time but not the first time?
The code uses a variable that has not been initialized, leading to unpredictable or unintended results. In some languages such as C and C++, stack variables are not initialized by default. They generally contain junk data with the contents of stack memory before the function was invoked.
In C and C++, local variables aren't initialized by default. Uninitialized variables can contain any value, and their use leads to undefined behavior.
When we declare a variable without initializing it, then it just stores some garbage value or zero value. But if we assign some value to it, then it will be overwritten with the new value.
Unlike some programming languages, C/C++ does not initialize most variables to a given value (such as zero) automatically. Thus when a variable is given a memory address to use to store data, the default value of that variable is whatever (garbage) value happens to already be in that memory address!
Apparently gcc
has a long running problem with false negatives with this option see this bug report: Bug 18501 - [4.8/4.9/5 Regression] Missing 'used uninitialized' warning (CCP) and the long list of duplicates:
Duplicates: 30542 30575 30856 33327 36814 37148 38945 39113 40469 42724 42884 45493 46684 46853 47623 48414 48643 49971 56972 57629 58323 58890 59225 60444
Note from comment towards the end, we can see this has been an ongoing issue for over ten years:
This year will be the 10 year anniversary of this bug. We should order cake!
Note, if you remove the:
scanf("%d",&sec);
you will also receive a warning, Marc Glisse also points out removing the first four printf
also works as well (see it live). I don't see a similar example in the duplicates but not sure it is work adding yet another bug report for this.
Also see Better Uninitialized Warnings which says:
GCC has the ability to warn the user about using the value of a uninitialized variable. Such value is undefined and it is never useful. It is not even useful as a random value, since it rarely is a random value. Unfortunately, detecting when the use of an uninitialized variable is equivalent, in the general case, to solving the halting problem. GCC tries to detect some instances by using the information gathered by optimisers and warns about them when the option -Wuninitialized is given in the command line. There are a number of perceived shortcomings in current implementation. First, it only works when optimisation is enabled through -O1, -O2 or -O3. Second, the set of false positives or negatives varies according to the optimisations enabled. This also causes high variability of the warnings reported when optimisations are added or modified between releases.
A side note, clang
seems to catch this case just fine (see live example):
warning: variable 'sec' is uninitialized when used here [-Wuninitialized]
printf("sec = %d\n",sec);
^~~
As I note in a comment below at least this case seems to be fixed in gcc 5.0
.
With this line:
scanf("%d",&sec);
GCC knows that you initialize sec
somewhere in your function.
As a separate step, GCC can do flow analysis to figure out whether you initialize sec
before using it. Unfortunately, GCC will not always do the flow analysis you want, or even do flow analysis at all. Sometimes the flow analyis is done at a stage where the other information is not available. So, you cannot count on GCC to figure it out.
Other compilers will figure it out. For example,
~ $ 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.
It just so happens that GCC is very bad at detecting these errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With