Why Do I See Strange Values When I Print Uninitialized Variables

Why uninitialized variable print a strange negative value?

What you're doing (reading the value of an uninitialised variable) is undefined behaviour; anything can happen, from it appearing to work, to printing random values, to crashing, to buying pizza with your credit card.

Strange behavior with uninitialized pointers

In general, just don't use uninitialized variables at all. If you want to know more, read on.

All your examples are straight Undefined Behavior (UB), due to this standard passage:

6.3.2.1 Lvalues, arrays, and function designators


[...]

2 [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

Now, let's pretend in some omitted line the address was taken.

&i; // Like this

6.2.4 Storage durations of objects


5 An object whose identifier is declared with no linkage and without the storage-class
specifier static has automatic storage duration, as do some compound literals. [...]

6 [...] The initial value of the object is indeterminate.

Alternative quote:

6.7.9 Initialization


[...]

10 If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate.

3.19.2


1 indeterminate value

either an unspecified value or a trap representation

3.19.3


1 unspecified value

valid value of the relevant type where this International Standard imposes no
requirements on which value is chosen in any instance

2 NOTE An unspecified value cannot be a trap representation.

3.19.4


1 trap representation

an object representation that need not represent a value of the object type

6.2.6.1 General


5 Certain object representations need not represent a value of the object type. If the stored
value of an object has such a representation and is read by an lvalue expression that does
not have character type, the behavior is undefined. If such a representation is produced
by a side effect that modifies all or any part of the object by an lvalue expression that
does not have character type, the behavior is undefined.50) Such a representation is called
a trap representation.

Thus, if your implementation supports trap-representations for the type you read (Yours don't for int*), you have UB.

Because you don't, unspecified value applies, which means every read returns some arbitrary value, and not neccessarily the same.


All quotes are from draft n1570, C99+Ammendments aka C11.

Inconsistency in uninitialized boolean variable

An uninitialiazed variable is just a piece of raw memory and will show as value whatever happes to be there. You idea that "In the live system it always happens to be true" is totally wrong. All you can say is that every time you observed it in the live system it seemed to be true. May be on next Tuesday instead it will happen to be false because it's well known that uninitialized bools hate tuesdays.

Note that's even entirely possible that an uninitialized boolean may seem true for one function and false for another (normally a full byte is allocated for a bool, but only a bit is needed to represent the value: it's possible that an uninitialized bool will contain a magic fuzzy bool value that it's true for someone and false for someone else).

As for what the standard says accessing an uninitialized variable for reading may indeed be undefined behavior, with no limits on what may happen including crashes (and for example is easy to have a program to "stop" when reading an uninitialized variable, just compile with a specific tool for tracking this kind of problem). Always having a program crash on accessing an uninitialized variable would be wonderful, but unfortunately it's quite costly on current CPUs and it's not going to happen unless specific tools are used.

Of course adding even just a printf call can change the apparent behavior of code handling uninitialized variables. This kind of bug is often referred to as "heisenbug" and actually the random or heisenbug behavior is often an indication of an uninitialized variable or of a thread synchronization problem.

What happens to a declared, uninitialized variable in C? Does it have a value?

Static variables (file scope and function static) are initialized to zero:

int x; // zero
int y = 0; // also zero

void foo() {
static int x; // also zero
}

Non-static variables (local variables) are indeterminate. Reading them prior to assigning a value results in undefined behavior.

void foo() {
int x;
printf("%d", x); // the compiler is free to crash here
}

In practice, they tend to just have some nonsensical value in there initially - some compilers may even put in specific, fixed values to make it obvious when looking in a debugger - but strictly speaking, the compiler is free to do anything from crashing to summoning demons through your nasal passages.

As for why it's undefined behavior instead of simply "undefined/arbitrary value", there are a number of CPU architectures that have additional flag bits in their representation for various types. A modern example would be the Itanium, which has a "Not a Thing" bit in its registers; of course, the C standard drafters were considering some older architectures.

Attempting to work with a value with these flag bits set can result in a CPU exception in an operation that really shouldn't fail (eg, integer addition, or assigning to another variable). And if you go and leave a variable uninitialized, the compiler might pick up some random garbage with these flag bits set - meaning touching that uninitialized variable may be deadly.



Related Topics



Leave a reply



Submit