Local variables are not static, but why am I getting this behavior?

When I teach C, sometimes I reckon that the GCC will fulfill the “convincing” part of some rules. For example, you should not consider that a local variable in a function stores a value between calls.

GCC has always helped me teach these lessons to students by putting garbage in local variables so that they understand what is going on.

Now this piece of code is definitely causing me a tough time.

#include <stdio.h> int test(int x) { int y; if(!x) y=0; y++; printf("(y=%d, ", y); return y; } int main(void) { int a, i; for(i=0; i<5; i++) { a=test(i); printf("a=%d), ", a); } printf("\n"); return 0; } 

Output:

 (y=1, a=1), (y=2, a=2), (y=3, a=3), (y=4, a=4), (y=5, a=5), 

But if I comment out the line:

  /* printf("(y=%d, ", y); */ 

Then the conclusion will be:

 a=1), a=32720), a=32721), a=32722), a=32723), 

I will compile the code using -Wall , but no warnings are associated with using local variables without initializing them.

Is there any GCC switch to trigger a warning, or at least explicitly show some kind of garbage? I tried the optimization switches, and that helped, as the code output became something like this:

 $ gcc test.c -o test -Wall -Os $ ./test (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), $ gcc test.c -o test -Wall -Ofast $ ./test (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), $ gcc test.c -o test -Wall -O0 $ ./test (y=1, a=1), (y=2, a=2), (y=3, a=3), (y=4, a=4), (y=5, a=5), $ gcc test.c -o test -Wall -O1 $ ./test (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), $ gcc test.c -o test -Wall -O2 $ ./test (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), $ gcc test.c -o test -Wall -O3 $ ./test (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), (y=1, a=1), 

But y = 1 in all cases is a kind of trick. Is the standard changed, so local variables are now initialized to zeros?

+6
source share
3 answers

Another possible approach to this idea could be to call another function between calls to the test function. If another function uses the stack space, then most likely this will lead to a change in the stack values. For example, it is possible to add a function like this:

 int changeStack( int x ) { int y2 = x + 100; return y2; } 

And then add a call to it:

  for(i=0; i<10; i++) { a=test(i); printf("a=%d), ", a); changeStack( i ); } 

Of course, it depends on the optimization levels, but with the default gcc test.c compilation ( gcc test.c ) I got the following results after changing it:

 (y=1, a=1), (y=101, a=101), (y=102, a=102), (y=103, a=103), (y=104, a=104), (y=105, a=105), (y=106, a=106), (y=107, a=107), (y=108, a=108), (y=109, a=109), 
+2
source

This problem is with undefined behavior: it is "undefined".

Thus, any set of results is completely reduced to a combination of the compiler / settings / what is in memory / interrupts.

You may have a chance at some settings that display what you expect to demonstrate the problem - but this is just luck.

What you find is actually more important is that the number of failure modes is wider than you can imagine (although, fortunately, none of them reformatted your hard drive), and that the most harmful and dangerous type undefined behavior "is that the behavior is actually" as expected "for 99.99% of the time.

This is the 0.01% that gets you.

+4
source

Your program invokes undefined behavior. If you pass a nonzero value to test() , y will never be initialized. printf included or not, you cannot rely on results.

If you need a warning, clang will give you one with -Wsometimes-uninitialized :

 example.c:6:12: warning: variable 'y' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized] if(!x) ^~ example.c:8:9: note: uninitialized use occurs here y++; ^ example.c:6:9: note: remove the 'if' if its condition is always true if(!x) ^~~~~~ example.c:5:14: note: initialize the variable 'y' to silence this warning int y; ^ = 0 1 warning generated. 

I tested a couple of versions of GCC that I have, but none of them warned me.

+2
source

Source: https://habr.com/ru/post/947237/


All Articles