In this case,
#include <stdio.h>
int main()
{
unsigned char a = 1;
printf("%hhu", -a);
return 0;
}
The argument -a
in printf
is promoted to int
by the integer promotion by the unary minus operator and subsequently promoted by the default argument promotion and finally converted to unsigned char
by the format specifier.
So -a
=> -(int)a
(by ~
) => no conversion by function call => (unsigned char)-(int)a
(by %hhu
). Is my thought right?
printf
is a variadic function. The type of the arguments passed by ...
parameter are not known inside the function. As such, any variadic function must rely on other mechanisms to interpret the type of the va_arg
s arguments. printf
and family use a const char* format
string to "tell them" what kind of arguments were passed. Passing a type different then the expected type as specified by it's format specifier results in Undefined Behavior.
For instance:
printf("%f", 24)
Is undefined behavior. There is no conversion from int
to float
anywhere because the arguments are passed as they are (after promotion) and inside the printf
the function incorrectly treats its first argument as float
. printf
does not know and can't know that the real type of the argument is int
.
Variadic arguments undergo some promotions of their own. Of interest for your question unsigned char
is promoted to int
or unsigned int
(I am not sure tbo). As such there is no way for a variadic parameter to actually be of type unsigned char
. So hhu
while is indeed the specifier for unsigned char
it will actually expect an unsigned int
(int
), which is what you pass to it.
So afaik the code is safe because of the two integer promotions caused by unary minus and passing variadic arguments. I am not 100% sure though. Integer promotions are weird and complicated.