Search code examples
clinuxgccgnu99

Bitwise "not" operator in C returns signed result


Consider this code:

uint16_t a = ~ ( uint16_t ) 0;
int16_t  b = ~ ( int16_t ) 0;
printf (
    "%d %d %d %d\n",
    a  == ~ ( uint16_t ) 0,
    a  == ( uint16_t ) ( ~ ( uint16_t ) 0 ),
    b  == ~ ( int16_t ) 0,
    b  == ( int16_t ) ( ~ ( int16_t ) 0 )
);

The output is:

0 1 1 1

GCC throws a warning about a == ~ ( uint16_t ) 0:

comparison is always false due to limited range of data type [-Wtype-limits]

Why is the bitwise "not" operator trying to return a signed value? How can I prevent that?


Solution

  • Why bitwise "not" operator is trying to return signed value?

    Because no operator works on types smaller than int; smaller types (including uint16_t if int has more than 16 bits) are promoted when used as operands. If all values of the original type are representable by int, as they are here, then the promotion will be to int.

    How can I prevent that?

    You can't; that's how the language works. You'll have to convert the result of the operator to the type you want, either implicitly as you do when initialising a, or explicitly with a cast. Note that you don't need the cast before applying ~; but for maximum portability, you should stick to unsigned types when doing bitwise logic:

    uint16_t a = ~0u;
    printf("%d\n", a == (uint16_t)~0u);  // Should print 1