# C++ Not-Zero Equality Trap

What would you expect this C++ code to do?

```
uint8_t val = ~0;
If (val == ~0) {
printf("YES!");
} else {
printf("NO!");
}
```

The result: `NO!`

How about this?

```
#define DO_TEST( TEST_TYPE ) \
{ \
TEST_TYPE val = ~0; \
if (val == ~0 ) { \
printf(#TEST_TYPE ": equal to ~0\n"); \
} else { \
printf(#TEST_TYPE ": NOT equal to ~0\n"); \
} \
} \
DO_TEST(uint8_t);
DO_TEST(uint16_t);
DO_TEST(uint32_t);
DO_TEST(uint64_t);
DO_TEST(int8_t);
DO_TEST(int16_t);
DO_TEST(int32_t);
DO_TEST(int64_t);
```

The result:

```
uint8_t: NOT equal to ~0
uint16_t: NOT equal to ~0
uint32_t: equal to ~0
uint64_t: equal to ~0
int8_t: equal to ~0
int16_t: equal to ~0
int32_t: equal to ~0
int64_t: equal to ~0
```

What is so different about `uint8_t`

and `uint16_t`

?
… And why do all the signed types seem unaffected?

Let’s update the test code to use a literal size-suffix:

```
if (val == ~0ll ) {
```

This will ensure that the literal is a 64-bit value. The new result:

```
uint8_t: NOT equal to ~0
uint16_t: NOT equal to ~0
uint32_t: NOT equal to ~0
uint64_t: equal to ~0
int8_t: equal to ~0
int16_t: equal to ~0
int32_t: equal to ~0
int64_t: equal to ~0
```

The `uint32_t`

test now fails also.

What is going on here?

The bitwise negation operator, `~`

, applied to `0`

results in a number with all bits set, regardless of the signed-ness.

Let’s write the `uint8_t`

expression another way by making `Val`

a literal as well:

```
0xff == ~0
```

This evaluates to `false`

also.

Let’s also expand out the `~0`

to the 32bit default int size.

```
0xff == 0xffffffff
```

We can see more clearly now that the values are indeed not equal.

But why does it succeed when `val`

has more bits than the 32 of default int?
… Automatic Integral Promotion!

Integral promotion is effective in ensuring that intermediate calculations involving smaller types do not overflow. In the case of the equality operator, both operands are expanded to the size of the larger of the two.

Let’s expand the expression for the `uint_64`

case:

```
0xffffffffffffffff == ~0x0000000000000000
```

After applying the binary negation, it is clearly `true`

:

```
0xffffffffffffffff == 0xffffffffffffffff
```

But what about the signed cases, which always work regardless of integral promotion?

Let’s look at the binary representation of `-1`

with varying type sizes:

8-bits: `11111111`

16-bits: `1111111111111111`

32-bits: `11111111111111111111111111111111`

The first bit indicates that this is a negative number. These negative numbers simply are interpretations of unsigned numbers that wrap around when counting below zero. This representation is known as Two’s Complement.

When integral promotion is applied, the numerical value of the negative number is maintained. On a binary level, this is effectively done by repeating the first, “sign bit”, to fill in the newly added bytes.

Although `~0`

stored in a `uint8_t`

and a `int8_t`

both have the same binary representation, the method of integral promotion applied by the compiler differs.

## Conclusion

Integral promotion in the expression comparing the two values occurs before the `~`

operator. Both the `~0`

and `val`

are promoted to the largest type between the two. If `val`

is the larger type, the condition can succeed; otherwise, it will always fail.

In the case of negative numbers, integral promotion extends the sign bit to maintain the same numerical value in two’s complement encoding. This results in the values continuing to be equal after promotion.