Seebs said:
I don't know about efficiency, but consider:
char x;
short x;
int x;
long x;
long long x;
Why should one of these five values default to unsigned, when the others
all default to signed?
Because one of them is used primarily to hold character codes, which
are normally thought of as unsigned values.
There is a conflict between the idea that char is a type used to old
character codes, and that char is a narrow integer type. The way C
has (mostly) resolved this conflict is steeped in historical accident,
and I think it would have been done quite differently if the language
were being designed from scratch today.
I would sort have preferred that 'signed' not be a keyword, and plain char
be always-signed. However, here we run into the essential clash between
'char' as thing to hold characters and 'char' as shortest basic integer
type.
Perhaps the correct solution would have been to use 'byte' and 'unsigned
byte', then have 'typedef <...> char_t' as the basic type used for strings,
etc.
Or make char a fundamental type that isn't part of the family of
integer types.
One example: In Ada, "Character" is an enumerated type, and character
literals like 'x' are permitted as enumerators.
A solution for a hypothetical C-like solution might be something like
this:
The integer types are byte, short, int, long, and long long
(or choose better names if you like). There are signed and
unsigned versions of each of these; each name by itself refers
to the signed version. For example, "byte" and "signed byte"
are different names for the same type; "unsigned byte" is another
type with the same size but a different range. (Or maybe "byte"
is an exception, with "byte" being an alias for "unsigned byte",
since unsigned bytes are more useful. Either way, the choice
is made by the language, *not* by the implementation.)
Type char is distinct from any of these types, and can hold
a single character value. char acts like an unsigned type,
in the sense that converting a char value to a sufficiently
wide type always yields a nonnegative value.
Deciding whether char is actually an integer type, and whether
conversions between char and (other) integer types may be done
implicitly, is left as an exercise.
Of course it's way too late to change C in this way.