11

The question arose in the comments of an answer to the question Is C/C++ bool type always guaranteed to be 0 or 1 when typecast'ed to int?

The code in question allocates a (local) array of bool without initializing their value.

const int n = 100;
bool b[n];

Clearly the values in b are indeterminate.

Some of the commenters opined that reading e.g. b[0] was undefined behavior. Is this stated anywhere in the C++ standard? I am still convinced of the opposite:

  1. There is clearly storage allocated and initialization of the fundamental bool type is complete, since it doesn't have a constructor. It is thus certainly not the same as dereferencing an uninitialized pointer, or calling methods/cast operators on uninitialized non-trivial objects. These specific cases seem to be covered by the standard.

  2. The behavior is indeed undefined in C: What happens to a declared, uninitialized variable in C? Does it have a value? and some respondents seem to confuse the two.

  3. In the latest C++0x draft I can find no definition of indeterminate value especially no definition that would allow accessing such a value to trigger a processor trap. Indeed, Bjarne Stroustrup is not sure what an inderminate value may be: http://zamanbakshifirst.blogspot.com/2007/02/c-indeterminate-value.html

Community
  • 1
  • 1
Sebastian
  • 4,802
  • 23
  • 48
  • 1
    Oh well, "Undefined behavior" is a very favourite term here in StackOverflow and it is used for everything from implementation defined, through unspecified upto the real undefined. – Šimon Tóth Nov 25 '10 at 16:54
  • 1
    I mean the proverbial "nasal demons" kind of undefined. – Sebastian Nov 25 '10 at 16:57
  • And btw. 8.5 - 9 talks about this. – Šimon Tóth Nov 25 '10 at 17:00
  • 2
    @Let_Me_Be: that may be true, and sometimes people might accidentally classify some case wrongly even though they understand the difference. But this is UB in the only sense that matters, which is the sense defined in the standard. – Steve Jessop Nov 25 '10 at 17:05
  • Note, my answer to [Is uninitialized local variable the fastest random number generator?](http://stackoverflow.com/a/31746063/1708801) is also relevant and we can see that compilers are actively taking advantage of undefined behavior around indeterminate values. – Shafik Yaghmour Sep 22 '15 at 14:56

4 Answers4

7

The answer to this question changes with the latest C++1y working draft(N3946) which we can find here. Section 8.5 Initializers paragraph 12 changes a lot from C++03 and C++11 and now contains the following (emphasis mine):

If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.17). [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:

and goes on to list some exceptions for unsigned narrow character type only, I have a complete quote in Has C++1y changed with respect to the use of indeterminate values and undefined behavior?.

So in your case b has automatic storage duration and is not initialized and therefore has indeterminate value. So evaluating b[0] is indeed undefined behavior.

Previously we were required to use the lvalue-to-rvalue conversion to prove this was undefined but that is problematic since the conversion is underspecified.

Note that indeterminate value is italicized in this section and therefore it means it is being defined in place and so now C++1y actually defines the term. Previously the term was used without a definition, this is covered in defect report 616.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
7

yes, formally an rvalue conversion of indeterminate value is UB (except for unsigned char, originally i wrote "and variants" but as i recall the formal caters to 1's complement signed char where possibly minus 0 could be used as trap value)

i'm too lazy to do the standard paragraph lookup for you, and also to lazy to care about downvotes for that

however, in practice only a problem on (1) archaic architectures, and perhaps (2) 64-bit systems.

EDIT: oops, i now seem to recall a blog posting and associated Defect Report about formal UB for accessing indeterminate char. so perhaps i'll have to actually check the standard, + search DRs. argh, it will have to be later then, now coffee!

EDIT2: Johannes Schaub was kind enough to provide this link to SO question where that UB for accessing char was discussed. So, that's where I remembered it from! Thanks, Johannes.

cheers & hth.,

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • @downvoter: please state reason for downvote so that others can learn what's wrong about an answer, or why your downvote is silly. – Cheers and hth. - Alf Nov 25 '10 at 17:01
  • 5
    +1. 4.1/1: "An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the lvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior." – Steve Jessop Nov 25 '10 at 17:01
  • 1
    Hey, I won't downvote you for your lazyness. However, I might not upvote for it either. – default Nov 25 '10 at 17:03
  • Thanks, I had found the relevant paragraph [conv.lval] in the latest FCD. However, `bool& br = b[0]` is not a prvalue but a glvalue if I'm not mistaken. The problem is then that everything I do to `br` (except assignment) requires the conversion to an rvalue, right? – Sebastian Nov 25 '10 at 17:11
  • And your link points to youtube.com, not a SO question. Fun certainly, but maybe not what you were going for :-) – Sebastian Nov 25 '10 at 17:13
  • @Sebastian: sorry, can't help you with C++0x, I don't understand those extra value types yet. I'm only talking about the standard. It seems unlikely to me that this would deliberately be made into defined behvaior in C++0x, though, since the only defined behavior I can think of is to say that the `bool` has a value (true or false), but it's unspecified which. In practice that means masking whenever a bool value is read from larger storage, for no benefit. – Steve Jessop Nov 25 '10 at 17:16
  • Interesting though that the proposed resolution in the DR linked to by Johannes, hasn't been implemented in the FCD (or n3126). – Steve Jessop Nov 25 '10 at 17:27
5

On bool, the standard says under 3.9.1 Fundamental types:

Values of type bool are either true or false.

With a footnote stating:

Using a bool value in ways described by this International Standard as “undefined,” such as by examining the value of an uninitialized automatic object, might cause it to behave as if it is neither true nor false.

UncleBens
  • 40,819
  • 6
  • 57
  • 90
1

The fact that reading an Indeterminate Value generally results in Undefined Behavior is not merely a "theoretical" issue. Even for types where all possible bit patterns have defined values, it should not be considered "surprising" for indeterminate values to behave in ways which differ from Unspecified values. For example, if *p holds Indeterminate Value, and x is not used anywhere except as shown, the code:

uint32_t x,y,z;
...
x = *p;
if (condition1) y=x;
... code that "shouldn't" affect *p if its value is defined
if (condition2) z=x;

could be rewritten as:

if (condition1) y=*p;
... code that "shouldn't" affect *p if its value is defined
if (condition2) z=*p;

If the value of *p is Indeterminate, a compiler would not be forbidden from having the code between the two "if" statements modify its value. For example, if the storage occupied by *p was occupied by a "float" before it freed and re-malloc'ed, the compiler might write that "float" value between the two "if" statements above.

supercat
  • 77,689
  • 9
  • 166
  • 211