Why does the complement behave differently through printf?

bitwise-operators, c, types, unsigned-char, variables

Solution

In this statement:

printf("%d",~c);

the `c` is converted to `int`1 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:

- `c` is a subject to integer promotions because of `~` (in the same way, as described above)

- `~c` rvalue is evaluated as (signed) `int` value (e.g. `-5`)

- `d=~c` makes an implicit conversion from `int` to `unsigned char`, as `d` has such type. You may think of it as the same as `d = (unsigned char) ~c`. Notice that `d` cannot be negative (this is general rule for all unsigned types).

- `printf("%d", d);` invokes default argument promotions, thus `d` is converted to `int` and the (nonnegative) value is preserved (i.e. the `int` type can represent all values of `unsigned char` type).

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).

Problem

I was reading a chapter on bitwise operators, I came across 1's complement operator program and decided to run it on Visual C++. ``` int main () { unsigned char c = 4, d; d = ~c; printf("%d\n", d); } ``` It gives the valid output: `251` Then instead of using `d` as a variable to hold the value of `~c`, I decided to directly print the value of `~c`. ``` int main () { unsigned char c=4; printf("%d\n", ~c); } ``` It gives the output `-5`. Why didn't it work?

Original source