In this statement:
printf("%d",~c);
the c is converted to int1 type before ~ (bitwise complement) operator is applied. This is because of integer promotions, that are invoked to operand of the ~. In this case an object of unsigned char type is promoted to (signed) int, which is then (after ~ operator evaluation) used by printf function, with matching %d format specifier.
Notice that default argument promotions (as printf is a variadic function) does not play any role here, as object is already of type int.
On the other hand, in this code:
unsigned char c = 4, d;
d = ~c;
printf("%d", d);
the following steps occur:
cis a subject to integer promotions because of~(in the same way, as described above)~crvalue is evaluated as (signed)intvalue (e.g.-5)d=~cmakes an implicit conversion frominttounsigned char, asdhas such type. You may think of it as the same asd = (unsigned char) ~c. Notice thatdcannot be negative (this is general rule for all unsigned types).printf("%d", d);invokes default argument promotions, thusdis converted tointand the (nonnegative) value is preserved (i.e. theinttype can represent all values ofunsigned chartype).
1) assuming that int can represent all values of the unsigned char (see T.C.’s comment below), but it is very likely to happen in this way. More specifically, we assume that INT_MAX >= UCHAR_MAX holds. Typically the sizeof(int) > sizeof(unsigned char) holds and byte consist of eight bits. Otherwise the c would be converted to unsigned int (as by C11 subclause §6.3.1.1/p2), and the format specifier should be also changed accordingly to %u in order to avoid getting an UB (C11 §7.21.6.1/p9).