"For signed integer types, the bits of the object
representation shall be divided into three groups: value bits,
padding bits, and the sign bit. There need not be any padding
bits; there shall be exactly one sign bit."
There is specifically no exemption for signed char, and plain
char if signed, as there is in the paragraph above for
unsigned char:
"For unsigned integer types other than unsigned char, the bits
of the object representation shall be divided into two groups:
value bits and padding bits (there need not be any of the
latter)."
So I see. I was convinced that there was.
On the other hand, there is a requirement that signed char,
unsigned char and char have the same size, and that all of the
non-negative values of a signed char have the same
representation as the value in an unsigned char. Or I think
there was in C90 (last night, I only had access to C90, where I
am now, I only have access to C99)---the change in wording in
C99 makes this less certain: "Each bit that is a value bit shall
have the same value as the same bit in the object representation
of the corresponding unsigned type." I suppose that this does
leave open the possibility of an implementation with 9 bit
bytes, all 9 bits being used for unsigned char, but signed char
with 1 bit sign, 1 bit padding and 7 value bits.
Of course, in C++, we also have the guarantee that char has no
trapping representations (which C explicitly doesn't give---only
unsigned char has this characteristic).
And I might add that I find it rather disappointing that C and
C++ have gone separated ways here. I would have liked for the
integral types in both languages to be compatible. Of course,
there is a compatible subset, and for very pratical reasons, all
implementations will implement something in that subset. Thus,
on the implementations where signed char might have a trapping
representation, plain char will be unsigned. Similarly,
historically, there's so much C code around that counts on being
able to copy char like the C standard guarantees for unsigned
char, and like C++ guarantees for char, that no implementation
would dare break it. But these things are important enough,
IMHO, that one would like to see them enshrined in the standard.