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?
You are correct that a
is promoted to int
in -a
, and that printf("%hhu", -a);
passes an int
to printf
. The notional conversion performed with %hhu
is not clear.
Note that if a
is not zero, then -a
produces a value (in an int
) that is not an unsigned char
value. Further, with two's complement eight-bit signed char
, if a
is greater than 128, then -a
produces a value that is not a signed char
value.
To understand %hhu
, we look at the specification for u
in C 2018 7.21.6.1 8:
The
unsigned int
argument is converted to unsigned octal (o), unsigned decimal (u),…
and for hh
in 7.21.6.1 7:
Specifies that a following d, i, o, u, x, or X conversion specifier applies to a
signed char
orunsigned char
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted tosigned char
orunsigned char
before printing);…
First we have to resolve this issue of “ signed char
or unsigned char
”. Does this say we can pass either a signed char
or an unsigned char
for %hhu
? I think not; I think the authors have just put together the language for %hhd
(intended to convert a signed char
) and %hhu
(intended to convert an unsigned char
). So I believe the intent is that a promoted unsigned char
should be passed for the %hhu
conversion specification.
Apple Clang 11.0.0 seems to agree, when passing -a
(but not a
), it warns: “warning: format specifies type 'unsigned char' but the argument has type 'int' [-Wformat]”
As noted above, passing -a
may pass a value that cannot result from passing a promoted unsigned char
. It may even pass a value that cannot result from passing a promoted signed char
or unsigned char
. In this case, it can be argued we have violated the requirement to pass an unsigned char
, and therefore the C standard does not specify the resulting behavior. Even though it says the passed value shall be converted to an unsigned char
, I believe that is a notional conversion, not a specific requirement on the library implementation, and that is also falls under the “as if” rules: It does not actually have to be performed if the resulting defined behavior of programs is the same. But, since passing an improper value may not be defined, we do not have defined behavior.
That may be a strict reading of the rules, but it would not surprise me greatly if printf
printed “4294967295” instead of “255” when a
were 1.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.