Keith Thompson said:
Not quite, but the phrasing is interesting:
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.
Such a representation is called a _trap representation_.
6.2.6.2 says that unsigned char cannot have padding bits;
since all CHAR_BIT bits are value bits, it cannot have any trap
representations. But 6.2.6.1p5 doesn't actually say that signed
or plain char cannot have trap representations, just that reading
a signed char trap representation doesn't cause undefined behavior.
(But then what is the behavior?)
An implementation with CHAR_BIT==8 might conceivably reserve the bit
pattern that would represent -128 as a trap representation.
I think the intent was that plain, signed, and unsigned char
cannot have trap representations, but I see a small loophole in
the current wording.
There is no question that signed char (and also char if it is the
same as signed char) can have trap representations. 6.2.6.1p5
allows it generically; 6.2.6.2p2 allows it specifically. In
all other cases when a type cannot have trap representations,
the Standard contains an explicit statement to that effect,
and there is no such statement for signed char.
Given that a signed char can have trap representations, we can ask
when happens when we read such objects, using an lvalue of type
signed char. Personally I think this is undefined behavior, but
suppose it's defined -- what's the definition? The only definition
that makes any sort of sense is to load the trap representation
"value" as the value of the access.
Having gotten this trap representation "value", what can we do with
it? We should be able to store it into another object of type
signed char, that seems obvious. What else? It can't be combined
using any arithmetic operation (converting to 'int' would be
undefined behavior), or compared to another value (again undefined
behavior on conversion). In fact converting to any other type at
all is undefined behavior, since the "value" doesn't exist in any
meaningful sense except in the context of the original type.
I suppose an argument could be made that such a "value" of type
'signed char' could be converted to type 'char' if char has the
same representation as signed char. But there doesn't seem to
be anything else that could be done with it in a well-defined way.
On a somewhat more pragmatic note, for implementations (assuming
any actually exist) that have such trap representations, the
implementations probably define the results of comparisons, at
least against zero, in a sensible way. So standard string
operations would likely work, even if technically they would
constitute undefined behavior. Actually it isn't that far fetched
that some implementations would have trap representations for
signed char, since all it would take is a ones' complement
or signed-magnitude representation without a negative zero.
Summing up: such trap representations are possible; if they exist
the only thing to do with them is copy them around; pragmatically
they are likely to behave reasonably and not trap (but of course
you never know when your friendly looking processor is going to
transmogrify from Dr. x86 to Mr. DS9000).
One additional note -- of course, implementations are free to
define undefined behavior any way they like, and in that sense
'signed char' trap representations could be seen has having
well-defined behavior. But the Standard itself doesn't define the
behavior under such conditions (except perhaps for the noted
operations of copying and signed char/char conversions).