Consider:
int x=0xdeadbeef;
char c=x;
printf("%x",c);
The output is ffffffef
.
How? Why is it NOT 000000ef
?
Consider:
int x=0xdeadbeef;
char c=x;
printf("%x",c);
The output is ffffffef
.
How? Why is it NOT 000000ef
?
A 32-bit integer does not fit inside an 8-bit char so char c=x;
is the same as c=0xef
.
Then apparently char
is signed on your compiler and 0xef
is larger than 127, so it gets converted to some negative value, -17.
When passed to printf
, the negative value char
gets promoted to int
, the sign is preserved (this is called "default argument promotion" and is used by all variadic functions). The 32-bit two's complement representation -17 is ffffffef
. With %x
you use the wrong format specifier; printf
expects unsigned int
. It tries to display the signed number as unsigned.
You can fix the bug by replacing char
with uint8_t
.
Overall, this code is very questionable, since it relies on lots of poorly-specified behavior. You shouldn't overflow signed integers, you shouldn't use char
for storing values, you should make an effort at using the correct format specifiers.
This is less a question of "how to format specifiers work" and more a "how does char
work".
A char
without any other type information can be either a signed or an unsigned value, which one is compiler-dependent. If you want a specific signedness, you should use unsigned char
or signed char
.
The %x
format instruction expects an unsigned int, so will (essentially) cast the char first to an int, then interpret that as an unsigned int. If your char is signed, it will get sign-extended as it's converted to an int and that's why you get the value you are seeing.