A few machines have what are called "trap representations". This means (for example) that an int
can contain an extra bit (or more than one) to signify whether it has been initialized or not.
If you try to read an int
with that bit saying it hasn't been initialized, it can trigger some sort of trap/exception/fault that (for example) immediately shuts down your program with some sort of error message. Any time you write a value to the int
, that trap representation is cleared, so reading from it can/will work.
So basically, when your program starts, it initializes all your int
s to such trap representations. If you try to read from an uninitialized variable, the hardware will catch it immediately and give you an error message.
The standard mandates that for unsigned char
, no such trap representation is possible--all the bits of an unsigned char
must be "visible"--they must form part of the value. That means none of them can be hidden; no pattern of bits you put into an unsigned char
can form a trap representation (or anything similar). Any bits you put into unsigned char
must simply form some value.
Any other type, however, can have trap representations. If, for example, you take some (more or less) arbitrarily chosen 8 bits out of some other type, and read them as an unsigned char
, they'll always form a value you can read, write to a file, etc. If, however, you attempt to read them as any other type (signed char
, unsigned int
, etc.) it's allowable for it to form a trap representation, and attempting to do anything with it can give undefined behavior.