If I have:
unsigned int x;
x -= x;
it’s clear that x should be zero after this expression, but everywhere I look, they say the behavior of this code is undefined, not merely the value of x (until before the subtraction).
Two questions:
-
Is the behavior of this code indeed undefined?
(E.g. Might the code crash [or worse] on a compliant system?) -
If so, why does C say that the behavior is undefined, when it is perfectly clear that
xshould be zero here?i.e. What is the advantage given by not defining the behavior here?
Clearly, the compiler could simply use whatever garbage value it deemed “handy” inside the variable, and it would work as intended… what’s wrong with that approach?
Yes this behavior is undefined but for different reasons than most people are aware of.
First, using an unitialized value is by itself not undefined behavior, but the value is simply indeterminate. Accessing this then is UB if the value happens to be a trap representation for the type. Unsigned types rarely have trap representations, so you would be relatively safe on that side.
What makes the behavior undefined is an additional property of your variable, namely that it "could have been declared with
register" that is its address is never taken. Such variables are treated specially because there are architectures that have real CPU registers that have a sort of extra state that is "uninitialized" and that doesn’t correspond to a value in the type domain.Edit: The relevant phrase of the standard is 6.3.2.1p2:
And to make it clearer, the following code is legal under all circumstances:
aandbare taken, so their value is justindeterminate.
unsigned charnever has trap representationsthat indeterminate value is just unspecified, any value of
unsigned charcouldhappen.
amust hold the value0.Edit2:
aandbhave unspecified values:Edit3: Some of this will be clarified in C23, where the term "indeterminate value" is replaced by the term "indeterminate representation" and the term "trap representation" is replaced by "non-value representation". Note also that all of this is different between C and C++, which has a different object model.