The correct one is*:
printf("%d",x);
This is because of default argument promotions as printf()
is variadic function. This means that unsigned char
value is always promoted to int
.
From N1570 (C11 draft) 6.5.2.2/6
Function calls (emphasis mine going forward):
If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed on
each argument, and arguments that have typefloat
are promoted to
double
. These are called the default argument promotions.
and 6.5.2.2/7
subclause tells:
The ellipsis notation in a function prototype declarator causes
argument type conversion to stop after the last declared parameter.
The default argument promotions are performed on trailing arguments.
These integer promotions are defined in 6.3.1.1/2
Boolean, characters, and integers:
If an
int
can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to anint
;
otherwise, it is converted to anunsigned int
. These are called the
integer promotions.58) All other types are unchanged by the integer
promotions.
This quote answers your second question of unsigned short
(see comment below).
* with exception to more than 8 bits unsigned char
(e.g. it might occupy 16 bit), see @chux’s answer.