unsigned
, int
and char
are so-called type specifiers. The rules in C about type specifiers are mighty weird and irrational, sometimes for backwards-compatibility reasons.
Chapter 6.7.2/2 of the C standard goes like this:
signed char
means signed char
.
unsigned char
means unsigned char
.
char
is a distinct type apart from the two above and can be either signed or unsigned. Depends on compiler.
short
, signed short
, short int
, or signed short int
means short
.
unsigned short
, or unsigned short int
means unsigned short
.
int
, signed
, or signed int
means int
.
unsigned
, or unsigned int
means unsigned int
.
long
, signed long
, long int
, or signed long int
means long
.
And so on. If you think that this system doesn't make much sense, it is because it doesn't.
Given the above, we can tell that unsigned char
and unsigned
are different types.
There is however a special case rule (called "the default argument promotions") for all variable-argument functions like printf
saying that all small integer types such as char
are implicitly promoted to type int
. That's why you can printf("%d"
on characters as well as integers. Similarly, %c
works for integers, because it is actually impossible for printf to get a real, non-promoted character type through its parameters. Anything of type int
or smaller will end up as int
on printf's side.