Why does the complement behave differently through printf?

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:

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

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)