- A+

Running the following program display -4 while 252 is expected:

`unsigned char a=3; printf ("%d", ~a); `

Why this code doesn't display 252?

I also tested the folowings according to the proposed answer:

`printf ("%u", ~a); `

displays: 4294967292

`printf ("%hu", ~a); `

displays: 65532

Why `~a`

doesn't return an `unsigned char`

since a **is** an `unsigned char`

?

My question is not what should I do to display 252 ? **My question is Why 252 is not displayed?**.

In addition to the answer of @Someprogrammerdude, here are the relevant passages from The Book^{1)}:

### Unary arithmetic operators (§6.5.3.3/4)

The result of the~operator is the bitwise complement of its (promoted[_{ }!!_{ }]) operand(that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set).The integer promotions are performed on the operand, and the result has the promoted type.If the promoted type is an unsigned type, the expression~Eis equivalent to the maximum value representable in that type minusE.

### Arithmetic operands - Boolean, characters, and integers (§6.3.1.1):

Every integer type has an integer conversion rank defined as follows:

- No two signed integer types shall have the same rank, even if they have the same representation.
- The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision.
- The rank of
long long intshall be greater than the rank oflong int, which shall be greater than the rank ofint, which shall be greater than the rank ofshort int, which shall be greater than the rank ofsigned char.- The rank of any
unsignedinteger type shall equal the rank of the corresponding signed integer type, if any.- The rank of any standard integer type shall be greater than the rank of any extended integer type with the same width.
- The rank of
charshall equal the rank ofsigned charandunsigned char.- The rank of
_Boolshall be less than the rank of all other standard integer types.- The rank of any enumerated type shall equal the rank of the compatible integer type (see 6.7.2.2).
- The rank of any extended
signedinteger type relative to another extendedsignedinteger type with the same precision is implementation-defined, but still subject to the other rules for determining the integer conversion rank.- For all integer types
T1,T2, andT3, ifT1has greater rank thanT2andT2has greater rank thanT3, thenT1has greater rank thanT3.The following may be used in an expression wherever an

intorunsigned intmay be used:

- An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of
intandunsigned int.- A bit-field of type
_Bool,int,signed int, orunsigned int.If anAll other types are unchanged by the integer promotions.intcan represent all values of the original type, the value is converted to anint; otherwise, it is converted to anunsigned int. These are called the integer promotions.^{48)}- The integer promotions preserve value including sign. As discussed earlier, whether a "plain"
charis treated assignedis implementation-defined.

^{48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.}

## Your Question:

Why

`~a`

doesn't return an`unsigned char`

since`a`

is an`unsigned char`

?

Because integer promotions apply.

`unsigned char a = 3; printf ("%d", ~a);`

`a`

is an `unsigned char`

, a type with a range that can be represented by an `int`

. So `a`

gets promoted to an `int`

. Assuming 32-bit wide `int`

s and two's complement:

3_{10} = `0000 0000 0000 0000 0000 0000 0000 0011`

_{2}

~3_{10} = `1111 1111 1111 1111 1111 1111 1111 1100`

_{2}

The result interpreted as `signed int`

is negative because the most significant bit, the sign bit, is set.

Convert to decimal:

`1111 1111 1111 1111 1111 1111 1111 1100`

_{2}

¬ `0000 0000 0000 0000 0000 0000 0000 0011`

_{2}

+ `0000 0000 0000 0000 0000 0000 0000 0001`

_{2}

────────────────────────────

`0000 0000 0000 0000 0000 0000 0000 0100`

_{2}

0100_{2} = 0 × 2^{3} + 1 × 2^{2} + 0 × 2^{2} + 0 × 2^{2}

_{ }= *1* × 2^{2}

_{ }= _{ }4_{10}

_{ }= −4_{10} (with the original sign)

### ~~> `printf()`

prints `-4`

.

To get the desired result of 252 with your original code which uses `"%d"`

as format specifier, some casting would be needed:

`unsigned char a = 3; printf("%d/n", (int)((unsigned char) ~a)); // prints 252 // ^^^ ^^^^^^^^^^^^^ // | cast the result of ~a back to unsigned char *) // | to discard the bits > CHAR_BIT // cast the char back to int to agree with the format specifier `

^{*)Thanks to chux who made me remember that char could be signed! A cast to (possibly signed) char would give the wrong result of -4.}

To get the same result without a cast, you could use the length modifier `hh`

:

### The fprintf function (§7.19.6.1/7)

The length modifiers and their meanings are:

hhSpecifies that a followingd,i,o,u,x, orXconversion specifier applies to asigned charorunsigned charargument (the argument will have been promoted according to the integer promotions, but its value shall be converted tosigned charorunsigned charbefore printing); or that a followingnconversion specifier applies to a pointer to a signed char argument.

[...]

`unsigned char a = 3; printf("%hhu/n", ~a); // prints 252 `

## The problem with your other attempts:

`printf ("%u", ~a);`

displays: 4294967292

`printf ("%hu", ~a);`

displays: 65532

Since `~a`

is an `int`

eger, it is not the correct type for the format specifier `u`

and

### The fprintf function (§7.19.6.1/9):

If a conversion specification is invalid, the behavior is undefined.

^{248)}If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

^{1) ISO/IEC 9899/Cor3:2007 aka C99:TR3 aka C99}