Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bit shift leads to strange type conversion

The following code compiles without warning:

std::uint16_t a = 12;
std::uint16_t b = a & 0x003f;

However, performing a bit shift along with the bitwise and leads to an 'implicit cast warning':

std::uint16_t b = (a & 0x003f) << 10; // Warning generated.

Both gcc and clang complain that there is an implicit conversion from int to uint16_t, yet I fail to see why introducing the bit shift would cause the right hand expression to suddenly evaluate to an int.

EDIT: For clang, I compiled with the -std=c++14 -Weverything flags; for gcc, I compiled with the -std=c++14 -Wall -Wconversion flags.

like image 859
Alessandro Power Avatar asked Apr 29 '16 14:04

Alessandro Power


People also ask

What happens when you shift bits?

Logical bit shifting may be useful for multiplying or dividing unsigned integers by powers of two. For example, if the value "0001" or "1" is shifted left, it becomes "0010" or "2," shifted to the left again it becomes "0100," or "4." Shifting to the right has an opposite effect of dividing the value by two per shift.

What is bit shifting in C++?

The bitwise shift operators are the right-shift operator (>>), which moves the bits of shift_expression to the right, and the left-shift operator (<<), which moves the bits of shift_expression to the left.

Does Java support bit shifting?

The Java programming language also provides operators that perform bitwise and bit shift operations on integral types.


1 Answers

Doing any arithmetic with integer types always is preceded by promotion to at least (sometimes, but not in this case using gcc, unsigned) int. As you can see by this example, this applies to you first, warning-less variant too.

The probably best way to get around these (admittedly often surprising) integer promotion rules would be to use an unsigned int (or uint32_t on common platforms) from the get go.

If you cannot or don't want to use the bigger type, you can just static_cast the result of the whole expression back to std::uint16_t:

std::uint16_t b = static_cast<std::uint16_t>((a & 0x003f) << 10); 

This will correctly result in the RHS-value mod 2^16.

like image 107
Baum mit Augen Avatar answered Oct 01 '22 18:10

Baum mit Augen