First to clarify, the quoted part from 6.3.2.1 addresses a special case, where you have an uninitialized variable which is not necessarily allocated at an address, because the address is never taken. Accessing such an object is explicitly undefined behavior. This is what the linked answer is concerned about.
If that special case does not apply, because the address is taken, then relvant parts would be 6.7.9/10:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
The definition of indeterminate value 3.19.2:
either an unspecified value or a trap representation
The definition of unspecified value 3.19.3:
valid value of the relevant type where this International Standard imposes no
requirements on which value is chosen in any instance
NOTE An unspecified value cannot be a trap representation.
And finally the part that says that accessing a trap representation is UB, 6.2.6.1/5, emphasis mine:
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.
To sum it up, an indeterminate value is not necessarily a trap representation and therefore, accessing an uninitialized variable is not necessarily undefined behavior.
There is, as far as I know, nothing in the standard explicitly saying that an unsigned character cannot hold a trap representation. 6.2.6.2 only says that they cannot have padding bits. Though in practice this would mean that an unsigned char
cannot hold a trap representation, because in order to do so it would either need padding bits or a signed format. So between the lines, I think it is safe to assume that unsigned char
cannot hold a trap representation.
However, I wonder whether volatile unsigned char foo; invokes undefined behaviour?
Declaring a variable never invokes undefined behavior in itself. If you access the variable without initializing it, then in the normal case, the value would be indeterminate. And it is implementation-dependent if this would be a trap representation or not.
However, volatile
is a special case and none of that applies. Instead you have 6.7.3/7: "... What constitutes an access to an object that
has volatile-qualified type is implementation-defined."
So it is simply implementation-defined behavior. Regardless of the type.
Also, is the following code well-defined?
unsigned char foo;
*&foo -= *&foo;
foo
has an indeterminate value. It's address is taken. So whether or not this is undefined behavior depends on if the indeterminate value is a trap representation or not, on the given system. As discussed above, I don't think an unsigned char
can ever be a trap representation.
However you used the -=
operator which would make this expression equivalent to
*&foo = *&foo - *&foo;
The binary -
operator promotes both operands to int
during calculation. If there were no trap representations to begin with, there could now be some in the promoted operands, which are of signed type, possibly with padding bits.
Meaning that this particular expression could invoke undefined behavior.