What is indeterminate behavior in C++ ? How is it different from undefined behavior?
The following remarks are based on the C standard, ISO-9899, rather than the C++ one, but the meanings are fundamentally the same (see sections 3.4 and 4 of the C standard; see also the C++ standard, ISO-14882, section 1.3; the latter document doesn't define 'unspecified value' as such, but does use that phrase later with the obvious meaning). The official standards documents are not free (indeed, they are expensive), but the links above are to the committee pages, and include free 'drafts' of the standard, which you can take to be essentially equivalent to the finalised standard text.
The terms describe a ladder of vagueness.
So, heading downwards....
Most of the time, the standard defines what should happen in a particular case: if you write c=a+b
and a
and b
are int
, then c
is their sum (modulo some details). This, of course, is the point of a standard.
Implementation-defined behaviour is where the standard lists two or more things which are allowed to happen in a particular case; it doesn't prescribe which one is preferred, but does demand that the implementation (the actual compiler which parses the C) makes a choice between the alternatives, does that same thing consistently, and that the implementation must document the choice it makes. For example, whether a single file can be opened by multiple processes is implementation-defined.
Unspecified behaviour is where the standard lists a couple of alternatives, each of which is therefore conformant with the standard, but goes no further. An implementation must choose one of the alternatives to pick in a particular case, but doesn't have to do the same thing each time, and doesn't have to commit itself in documentation to which choice it will make. For example, the padding bits in a struct
are unspecified.
Undefined behaviour is the most extreme case. Here, all bets are off. If the compiler, or the program it generates, runs into undefined behaviour, it can do anything: it can scramble memory, corrupt the stack, HCF or, in the standard extreme case, cause demons to fly out of your nose. But mostly it'll just crash. And all of these behaviours are conformant with the standard. For example, if a variable is declared both static int i;
and int i;
in the same scope, or if you write #include <'my file'.h>
, the effect is undefined.
There are analogous definitions for 'value'.
An unspecified value is a valid value, but the standard doesn't say what it is. Thus the standard might say that a given function returns an unspecified value. You can store that value and look at it if you want to, without causing an error, but it doesn't mean anything, and the function might return a different value next time, depending on the phase of the moon.
An implementation-defined value is like implementation-defined behaviour. Like unspecified, it's a valid value, but the implementation's documentation has to commit itself on what will be returned, and do the same thing each time.
An indeterminate value even more unspecified than unspecified. It's either an unspecified value or a trap representation. A trap representation is standards-speak for some magic value which, if you try to assign it to anything, results in undefined behaviour. This wouldn't have to be an actual value; probably the best way to think about it is "if C had exceptions, a trap representation would be an exception". For example, if you declare int i;
in a block, without an initialisation, the initial value of the variable i
is indeterminate, meaning that if you try to assign this to something else before initialising it, the behaviour is undefined, and the compiler is entitled to try the said demons-out-of-nose trick. Of course, in most cases, the compiler will do something less dramatic/fun, like initialise it to 0 or some other random valid value, but no matter what it does, you're not entitled to object.
The point of all this imprecision is to give maximal freedom to compiler writers. That's nice for compiler writers (and is one of the reasons it's reasonably easy to get a C compiler running on such a huge range of platforms), but it does make things rather more interesting than fun for the poor users.
Edit 1: to clarify indeterminate values.
Edit 2: to include a link to the C++ standard, and note that the committee drafts are essentially equivalent to the final standard, but free.
I think the standard mentions undefined behaviour and indeterminate value. So one is about the behaviour and another about values.
These two are somewhat orthogonal, for example, the behaviour can still be well defined in the presence of indeterminate values.
EDIT 1: The last drafts of C11 and C++11 are available online here: C11 draft N1570 and C++11 draft n3242 if you don't have a copy of the final standards and wonderful what they look like. (Other adjustments to text appearance and some wording/grammar edits have been done.)
EDIT 2: Fixed all occurrences of "behaviour" to be "behavior" to match the standard.
Searching the C++11 and C11 standards there are no matches for indeterminate rule or undefined rule. There are terms like indeterminate value, indeterminately sequenced, indeterminate uninitialized, etc.
If talk of traps and exceptions seems weird in Norman Gray's answer, know that those terms do reflect the relevant definitions in Section 3 in the C11 standard.
C++ relies on C's definitions. Many useful definitions concerning types of behaviour can be found in C11's Section 3 (in C11). For example, indeterminate value is defined in 3.19.2. Do take note that C11's Section 2 (Normative References) provides other sources for additional terminology interpretation and Section 4 defines when cases such as undefined behavior occur as a result of not complying with the standard.
C11's section 3.4 defines behavior, 3.4.1 defines implementation-defined behavior, 3.4.2 defines locale-specific behavior, 3.4.3 defines undefined behavior, 3.4.4 defines unspecified behavior. For value (Section 3.19), there are implementation-defined value, indeterminate value, and unspecified value.
Loosely speaking, the term indeterminate refers to an unspecified/unknown state that by itself doesn't result in undefined behavior. For example, this C++ code involves an indeterminate value: { int x = x; }. (This is actually an example in the C++11 standard.) Here x is defined to be an integer first but at that point it does not have a well-defined value --then it is initialized to whatever (indeterminate/unknown) value it has!
The well-known term undefined behavior is defined in 3.4.3 in C11 and refers to any situation of a
nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
In other words undefined behavior is some error (in logic or state) and whatever happens next is unknown! So one could make an undefined [behavior] rule that states: avoid undefined behavior when writing C/C++ code! :-)
An indeterminate [behavior] rule would be to state: avoid writing indeterminate code unless it is needed and it does not affect program correctness or portability. So unlike undefined behavior, indeterminate behavior does not necessarily imply that code/data is erroneous, however, its subsequent use may or may not be erroneous --so care is required to ensure program correctness is maintained.
Other terms like indeterminately sequenced are in the body text (e.g., C11 5.1.2.3 para 3; C++11, section 1.9 para. 13; i.e., in [intro.executation]). (As you might guess, it refers an unspecified order of operational steps.)
IMO if one is interested in all of these nuances, acquiring both the C++11 and C11 standards is a must. This will permit one to explore to the desired level-of-detail needed with definitions, etc. If you don't have such the links provided herein will help you explore such with the last published draft C11 and C++11 standards.