Any guarantees for uninitialized variables?

There are many claims that any use of uninitialized variables causes undefined behavior (UB) .
Looking through the documents, I could not verify this requirement, so I would like to get a convincing argument explaining this for both C and C ++.
I expect the same semantics for both, but I'm ready to marvel at the subtle or not-so-subtle differences.

Some examples of using uninitialized variables to get you started. Please add others if necessary to explain any angular cases that they do not cover.

void test1() { int x; printf("%d", x); } void test2() { int x; for(int i = 0; i < CHAR_BIT * sizeof x) x = x << 1; printf("%d", x); } void test3() { unsigned x; printf("%u", x); /* was format "%d" */ } void test4() { unsigned x; for(int i = 0; i < CHAR_BIT * sizeof x) x = x << 1; printf("%u", x); /* was format "%d" */ } 
-four
c undefined-behavior
Apr 03 '14 at 13:36 on
source share
4 answers

In C, they are all undefined behavior, but for the reason that it probably doesn’t come straight to the head. Access to an object with an undefined value has undefined behavior if it is "without memory", that is, 6.3.2.1 p2

If lvalue denotes an object with automatic storage time, which can be declared with a register storage class (its address has never been), and this object is uninitialized (not declared with an initializer and no assignment to it was made earlier for use), the behavior is undefined.

Otherwise, if the address is made, the interpretation of what vaguely means specifically in this case is not unanimous. There are people who expect this value to be fixed after its first reading, others say something like “woobly” (or so) values ​​that may be different with every access.

In short, do not do this. (But you probably already knew.)

(And not to mention the error using "% d" for unsigned .)

+9
Apr 03 '14 at 13:52 on
source share

FROM

C11 6.7.9 / 10

If an object with automatic storage duration is not initialized explicitly, its value is undefined.

Undefined values ​​are processed as follows:

C11 6.2.6.1/5

Certain representations of objects do not have to represent the value of an object type. If the stored value of an object has that representation value and is read by an lvalue expression that does not have a character type, the behavior is undefined. If such a representation is created by a side effect that changes all or any part of the object with an lvalue expression that does not have a character type, the behavior is undefined 50). Such a view is called a trap view.

Comment on the above regulatory text:

50) Thus, an automatic variable can be initialized to trap a view without undefined behavior , but the value of the variable cannot be used until the correct value is stored in it.

(my accent)

In addition, a left shift of the int int variable containing an undefined value can also lead to undefined behavior if it is interpreted as negative:

C11 6.5.7 / 4

Result E1 <E2 - left shifted positions E2; freed bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value represented in the result type. If E1 has a signed type and a non-negative value and E1 × 2E2 is presented as a result, then this is the resulting value; otherwise, the behavior is undefined.

+7
Apr 03 '14 at
source share

All four cases cause undefined behavior in C, since an uninitialized automatic variable never has its address. See Another answer.

By the way, sizeof(x) is defined because the expression is not actually evaluated: it is an estimate of the compilation time, which decays into a type.

In the latest C ++ 1y project ( N3936 ), this is clearly undefined behavior, since the language of undefined values ​​and undefined behavior have been refined , and now it says in section 8.5 :

[...] If an undefined value is created by an estimate, the behavior is undefined, except in the following cases:

and further lists the exception for only certain types of unsigned characters.

In C ++, we used to rely on underspecified lvalue-to-rvalue conversion to prove undefined behavior, which is problematic in the general case. In this case, we have a lalue-to-rvalue conversion. If we look at section 5.2.2 Calling function 7, which reads (emphasis mine):

If there is no parameter for this argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by calling va_arg (18.10). [...] The value lvalue-to-rvalue (4.1) , the pointer variable (4.2) and the to-pointer function (4.3) standard transformations are performed with the argument expression .

+3
Apr 03 '14 at 13:38 on
source share

With respect to C, the behavior of all examples can equally be undefined:

Chapter and verse

<3.19.2
1 undefined value
either nonspecific or trap representation
...
6.2.6 Type Representations
6.2.6.1 General
...
5 Some representations of objects do not have to represent an object type value. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character, the behavior is undefined. If such a representation is created by a side effect that changes all or any part of an object through an lvalue expression that is not character, the behavior is undefined. 50) This representation is called the representation of the trap.
...
50) Thus, an automatic variable can be initialized into a trap view without causing undefined behavior, but the value of the variable cannot be used until the correct value is stored in it.

In all four cases, x has an automatic storage duration and is not explicitly initialized, that is, its value is indefinite; if this undefined value is a trap representation, then the behavior is undefined.

EDIT

The link to the application J has been deleted, since it is not normative.

+3
Apr 03 '14 at 2:09
source share



All Articles