First of all, char
may be signed or unsigned depending on compiler and is therefore unsuitable for storying raw binary, see Is char signed or unsigned by default?.
In your case it is apparently signed, in which case the value 0b11111111 = 255 won't fit. Upon assignment, 255 will get implicitly converted to the signed char
in a compiler-specific way. Very likely as the 2's complement number -1
.
Now as you pass any small integer type to printf
, they get implicitly promoted by an oddball rule called default argument promotions, which applies to all variable number of argument functions. This rule goes:
the integer promotions are performed on each argument, and arguments that
have type float are promoted to double
For the meaning of "small integer type" and integer promotion, please check Implicit type promotion rules.
This means that what's passed to printf
is an int
, still with value -1 but sign extended. Since int
is likely something like 4 byte, it now contains the raw binary 0xFFFFFFFF instead of just 0xFF. Which is still the decimal number -1
, just a larger type.
Then finally you tell printf
to print it as unsigned int
, so it gets converted by printf
to the unsigned representation of 0xFFFFFFFF
. This is a well-defined conversion (C17 6.3.1.3):
Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or
subtracting one more than the maximum value that can be represented in the new type
until the value is in the range of the new type.
And you will end up with 2^32 - 1 = 4294967295 on a 32 bit int
computer.