Auto Initialization of local variables - c

I have the following code snippet.
int j;
printf("%d",j);
As expected, I get a garbage value.
32039491
But when I include a loop in the above snippet, like
int j;
print("%d",j);
while(j);
I get the following output on multiple trials of the program.
0
I always thought local variables are initialized to a garbage value by default, but it looks like variables get auto initialized when a loop is used.

It is having indeterminate value. It can be anything.
Quoting C11 §6.7.9
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. [...]
Automatic local variables, unless initialized explicitly, will contain indeterminate value. In case you try to use a variable while it holds indeterminate value and either
does not have the address taken
can have trap representation
the usage will lead to undefined behavior.

As expected, I get a garbage value.
Then your expectation is unjustifiably hopeful. When you use the indeterminate value of an uninitialized object, you generally get (and for your code snippets alone you do get) undefined behavior. Printing a garbage value is but one of infinitely many possible manifestations.
I always thought local variables are initialized to a garbage value by default, but it looks like variables get auto initialized when a loop is used.
You thought wrong, and you're also drawing the wrong conclusion. Both of your code snippets, when standing alone, exhibit undefined behavior. You cannot safely rely on any particular result.

Related

In C, I'm struggling with Pointers

I have this code that I'm using for something else, but, boiled it down to the root problem I think. If I enter 5 for the scanf variable when I run it, the printf out is 0,16. I don't understand why this is giving me 16 for *pScores?
#include <stdio.h>
int main(void) {
int a=0;
int sum=0;
scanf("%d",&a);
int scores[a];
int *pScores = &scores[0];
printf("%d, %d\n",scores[0],*pScores);
}
You are declaring an array
int scores[a];
and then printing out the value of scores[0] in two different ways. However, you have not stored anything into any of the elements of the scores array, so the values there are indeterminate.
Whether use of uninitialized (and therefore indeterminate) values in this way actually rises to the level of Undefined Behavior is a surprisingly deep and actually somewhat contentious question. (See the comment thread raging at the other answer.) Nevertheless, printing an uninitialized value like this isn't terribly useful. If you fill in a well-defined value to at least scores[0], I believe you'll find that both scores[0] and *pScores will print the same — that same — value.
Now, you might expect that the uninitialized value — whatever it is — would at least be consistent no matter how you print it (and I might agree with you), but when it comes to gray areas like this, and especially when a modern compiler starts leveraging every nuance of the rules in performing aggressive optimizations, the end results can be pretty surprising. When I tried your program, I got the same number printed twice (that is, I couldn't initially reproduce your result), but as suggested by Barmar in a comment, when I turned on optimization (with -O3), I started seeing conflicting results, also.
You have undefined behavior, caused by reading a variable with automatic storage duration whose value is indeterminate.
In 6.2.4 Storage durations of objects one finds the following rule
For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration. If the scope is entered recursively, a new instance of the object is created
each time. The initial value of the object is indeterminate.
Then in J.2 Undefined behavior:
The behavior is undefined in the following circumstances
...
The value of an object with automatic storage duration is used while it is indeterminate.
...
Among permitted very weird outcomes when dealing with indeterminate values is that they have a different value each time you read them. The Schroedinger wavefunction does not collapse!

C : Passing auto variable by reference

I came across a piece of code which is working fine as of now,but in my opinion its undefined behavior and might introduce a bug in future.
Pseudo code :
void OpertateLoad(int load_id)
{
int value = 0;
/* code to calculate value */
SetLoadRequest(load_id,&value);
/*some processing not involving value**/
}
void SetLoadRequest(int load_id, int* value)
{
/**some processing**/
LoadsArray[load_id] = *value;
/**some processing**/
}
In my understanding C compiler will not guarantee where Auto variables will be stored. It could be stack/register(if available and suitable for processing).
I am suspecting that if compiler decides to store value onto general purpose register then, SetLoadRequest function might refer to wrong data.
Am I getting it right?or I am overthinking it?
I am using IARARM compiler for ARM CORTEX M-4 processor.
----------:EDIT:----------
Answers Summarize that " Compiler will ensure that data is persisted between the calls, no matter where the variable is stored ".
Just want to confirm : Is this behavior also true 'if a function is returning the address of local auto variable and caller is de-referencing it?'.
If NO then is there anything in C standard which guarantees the behavior in both cases? Or As I stated earlier its undefined behavior?
You are overthinking it. The compiler knows that, if value is in a register, that it must be stored to memory before passing a pointer to that memory to SetLoadRequest.
More generally, don't think about stack and registers at all. The language says there's a variable (without saying how it's implemented), and that you can take its address and use that in another function to refer to the variable. So you can!
The language also says that local variables cease to exist when leaving a block, so this permission does not extend to returning pointers to local variables (which causes undefined behavior if the caller does anything at all with the pointer).
I am overthinking it?
Yes!
The compiler will take care of this. If it stores it in a register, it will know how to handle it (with a memory load).
C11 draft standard n1570:
6.2.4 Storage durations of objects
6 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration or
compound literal is reached in the execution of the block; otherwise, the value becomes
indeterminate each time the declaration is reached.
To my understanding, the scope of value is the body of OpertateLoad. However, SetLoadRequest assigns the value pointed to, so the actual value of value is copied. No undefined behaviour is involved.

Variable initailization after being called is reflected beforehand

I am learning about scoping of variable in C.
Can anyone please explain what is going on below?
int w;
printf("\nw=%d\n", w);
w =-1;
Despite the fact that I initialized variable 'w' after 'printf', it always gets the value of "-1". This confused me, as I expect it to run sequentially. Hence, it should have printed some random value.
*** I also tried changing the value there, and it always read the written value. Hence, it did not randomly show "-1"
For experiment, I again tried the code below.
int w;
printf("\nw=%d\n", w);
w =-9;
w =-1;
Now, it reads a value of "2560". As I expect since it was not properly initialized before.
In your code
int w;
printf("\nw=%d\n", w);
invokes undefined behavior as you're trying to read the value of an uninitialized (automatic local) variable. The content of w is indeterminate at this point, and the output result is, well, undefined.
Always initialize your local variable before reading (using) the value.
Related: Quoting C11, chapter §6.7.9, Initialization
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. [....]
and, related to Undefined behavior, annex §J.2
The value of an object with automatic storage duration is used while it is
indeterminate
The variable in uninitialized. In "C", this means its value is "nondeterministic". In reality, the variable generally gets a value based on what's "laying around" at the memory address to which it gets assigned. In this case, its some value left on the stack.
It just so happens that often you will get consistent results across multiple runs simply due to external factors on which a program should not rely.
The compiler is optimizing the assignment of w in the first case. In the second case, it is deciding not to optimize.
In both cases, the compiler could choose to optimize out both assignments, since w is not used after they appear.
Initialize your variables before using them.
In both the above cases
int w;
printf("\nw=%d\n", w);
returns a random garbage value as we might call it which could be anything including -1 or 2560.
Blockquote
When you do not initialize a variable it can contain garbage value. Hence it's undefined behaviour and in most cases it will print random numbers as you experienced. By the way, as pointed out by others it's up to the compiler, so it may work with the expected value or it may don't work.

Default value to non initialized variables

I'm reading this tutorial about debugging. I pasted the factorial code in my .c archive:
#include <stdio.h>
int main()
{
int i, num, j;
printf ("Enter the number: ");
scanf ("%d", &num );
for (i=1; i<num; i++)
j=j*i;
printf("The factorial of %d is %d\n",num,j);
}
When I run the executable, it always print 0, however, the author of the tutorial says that it return numbers garbage value. I've googled about this and I've read that this is right, except for static variables. So it should return a garbage number instead of 0.
I thought that this might be due to a different version of C, but the guide is from 2010.
Why do I always see 0, instead of a garbage value?
Both the C99 draft standard and the C11 draft standard say the value of an uninitialized automatic variable is indeterminate, from the draft c99 standard section 6.2.4 Storage durations of objects paragraph 5 says (emphasis mine):
For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. (Entering an enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes indeterminate each
time the declaration is reached.
the draft standard defines indeterminate as:
either an unspecified value or a trap representation
and an unspecified value is defined as:
valid value of the relevant type where this International Standard imposes no
requirements on which value is chosen in any instance
so the value can be anything. It can vary with the compiler, optimization settings and it can even vary from run to run but it can not be relied and thus any program that uses a indeterminate value is invoking undefined behavior.
The standard says this is undefined in one of the examples in section 6.5.2.5 Compound literals paragraph 17 which says:
Note that if an iteration statement were used instead of an explicit goto and a labeled statement, the lifetime of the unnamed object would be the body of the loop only, and on entry next time around p would have an indeterminate value, which would result in undefined behavior.
this is also covered in Annex J.2 Undefined behavior:
The value of an object with automatic storage duration is used while it is
indeterminate (6.2.4, 6.7.8, 6.8).
In some very specific cases you can make some predictions about such behavior, the presentation Deep C goes into some of them. These types of examination should only be used as a tool to further understand how systems work and should never even come close to a production system.
You need to initialize j to 1. If j happens to be zero, the answer will always be zero (one type of garbage). If j happens to non-zero, you'll get different garbage. Using uninitialized variables is undefined behaviour; 'undefined' does not exclude always being zero in the tests you've done so far.
Some systems have their memory set to 0 (Mac OS for example) so your variable will often contain 0 when you initialise it but it's a bad practice that will lead to unstable results.
You can't say what should happen in this case because the language specification doesn't say what should happen. In fact it says that the values of uninitialised non-static variables are indeterminate.
That means they can be any value. They can be different values on different runs of your program, or when your code is compiled on a different compiler, or when compiled on the same compiler with different optimisation settings. Or on different days of the week, national holidays or after 6pm.
An uninitialised variable can even hold what's called a trap representation, which is a value which is not valid for that type. If you access such a value then you're into the scary world of undefined behaviour where literally anything can happen.

Local variable still exists after function returns

I thought that once a function returns, all the local variables declared within (barring those with static keyword) are garbage collected. But when I am trying out the following code, it still prints the value after the function has returned. Can anybody explain why?
int *fun();
main() {
int *p;
p = fun();
printf("%d",*p); //shouldn't print 5, for the variable no longer exists at this address
}
int *fun() {
int q;
q = 5;
return(&q);
}
There's no garbage collection in C. Once the scope of a variable cease to exist, accessing it in any means is illegal. What you see is UB(Undefined behaviour).
It's undefined behavior, anything can happen, including appearing to work. The memory probably wasn't overwritten yet, but that doesn't mean you have the right to access it. Yet you did! I hope you're happy! :)
If you really want it to loose the value, perhaps call another function with at least a few lines of code in it, before doing the printf by accessing the location. Most probably your value would be over written by then.
But again as mentioned already this is undefined behavior. You can never predict when (or if at all) it crashes or changes. But you cannot rely upon it 'changing or remaining the same' and code an application with any of these assumptions.
What i am trying to illustrate is, when you make another function call after returning from previous one, another activation record is pushed on to the stack, most likely over writing the previous one including the variable whose value you were accessing via pointer.
No body is actually garbage collecting or doing a say memset 0 once a function and it's data goes out of scope.
C doesn't support garbage collection as supported by Java. Read more about garbage collection here
Logically, q ceases to exist when fun exits.
Physically (for suitably loose definitions of "physical"), the story is a bit more complicated, and depends on the underlying platform. C does not do garbage collection (not that garbage collection applies in this case). That memory cell (virtual or physical) that q occupied still exists and contains whatever value was last written to it. Depending on the architecture / operating system / whatever, that cell may still be accessible by your program, but that's not guaranteed:
6.2.4 Storage durations of objects
2 The lifetime of an object is the portion of program execution during which storage is
guaranteed to be reserved for it. An object exists, has a constant address,33)
and retains
its last-stored value throughout its lifetime.34)
If an object is referred to outside of its
lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when
the object it points to (or just past) reaches the end of its lifetime.
33) The term ‘‘constant address’’ means that two pointers to the object constructed at possibly different
times will compare equal. The address may be different during two different executions of the same
program.
34) In the case of a volatile object, the last store need not be explicit in the program.
"Undefined behavior" is the C language's way of dealing with problems by not dealing with them. Basically, the implementation is free to handle the situation any way it chooses to, up to ignoring the problem completely and letting the underlying OS kill the program for doing something naughty.
In your specific case, accessing that memory cell after fun had exited didn't break anything, and it had not yet been overwritten. That behavior is not guaranteed to be repeatable.

Resources