The bitwise not operator in C returns the 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 ) ); 

Output:

0 1 1 1

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

the comparison is always incorrect due to the limited range of data types [-Wtype-limits]

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

+4
source share
2 answers

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

Since the operator does not work with types less than int ; smaller types (including uint16_t if int has more than 16 bits) advance when used as operands. If all values โ€‹โ€‹of the original type are represented by int , as they are here, then the promotion will be int .

How can I prevent this?

You can not; how the language works. You will need to convert the result of the operator to the type you need, either implicitly, as in the initialization of a , or explicitly using a throw. Please note that before applying ~ you do not need a throw; but for maximum portability, you should stick with unsigned types when executing bitwise logic:

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

A sign is a concept that lies on top of bit patterns. Bitwise not (~) refers only to the bitmap, and not to the sign of the value. The result of canceling a signed unsigned value is identical.

Having said that, looking at the C standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf (a draft version is available for free). Section 6.3.1.4, page 51:

If int can represent all values โ€‹โ€‹of the original type (limited by the width for the bit field), the value is converted to int; otherwise, it will be converted to unsigned int. They are called whole stocks. (58) All other types are not modified by whole promotions.

I believe this means that char and short types will be upgraded to int (or unsigned int depending on size) when we actually work on them. This makes sense because we want operations to be performed as fast as possible, so we must focus on the machineโ€™s own size.

Given this, we can see what is really happening. The machine will perform all operations with the size "int", since both operands in "==" and "~" can fit in the int field that I assume on your computer is 32 bits.

Now the first thing you need to pay attention to is the value of 'a'. Take 0, we donโ€™t get and get 0xFFFFFFFF. We assign this value to uint16_t and get 0xFFFF. When we are ready to perform the comparison, we will load 0xFFFF, we will understand that the unsigned value and zero extend it to 0x0000FFFF. For the value of the value "b" everything is the same, except when we read 0xFFFF for comparison, which we sign, bringing it to 0xFFFFFFFF. Now for your cases:

  • Zero notation gives 0xFFFFFFFF, and compared to 0x0000FFFF it will fail.
  • We took our 0xFFFFFFFF, cut it into 0xFFFF, and then zero expanded it to 0x0000FFFF, specifying the same value as 'a'.

And so on.

+3
source

Source: https://habr.com/ru/post/1480229/


All Articles