Variable arguments are subject to the default argument promotion, eg char
will be promoted to int
, float
to double
(that's the reason why you only have a single format specifier to print both single and double precision floating point values).
So passing an int
instead of a char
is perfectly valid and even desirable, as character literals are of type int
anyway. According to the C99 spec, section 7.19.6.1 §8, on seeing the conversion specifier %c
, printf()
expects an argument of type int
and will then go on and cast this value to unsigned char
.
This means the following is guaranteed to output a
, as conversion of signed to unsigned types is well-defined:
int a = 'a' + UCHAR_MAX + 1;
printf("%c", a);