I'm getting results from left shift to which I could not find an explanation.
unsigned char value = 0xff; // 1111 1111
unsigned char = 0x01; // 0000 0001
std::cout << "SIZEOF value " << sizeof(value) << "\n"; // prints 1 as expected
std::cout << "SIZEOF shift " << sizeof(shift) << "\n"; // prints 1 as expected
std::cout << "result " << (value << shift) << "\n"; // prints 510 ???
std::cout << "SIZEOF result " << sizeof(value << shift) << "\n"; // prints 4 ???
I was expecting result to be 1111 1110
but instead I get int
(?) with value of 1 1111 1110
.
How can the bits of an unsigned char be shifted to the left so that bits are truncated and the result is 1111 1110?
What I'm trying to do is to read series of bytes and interpret them as integers of varying lengths (1-32 bits).
F0 F5
1111 0000 1111 0101
could be
0F (first 4 bits)
0F (next 8 bits)
05 (last 4 bits)
Has this something to do with the fact that arithmetic is not done with types smaller than int?
Quoting some draft of the 2011 standard:
5.8 Shift operators [expr.shift]
...
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand.
and
4.5 Integral Promotions [conv.prom]
A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int
...
So, value
is promoted to int
, and the type of value << shift
is the type of the promoted left operand, i.e. int
.
You can achieve your desired result one of these ways:
std::cout << "result " << ((unsigned char)(value << shift)) << "\n";
std::cout << "result " << ((value << shift)&0xff) << "\n";
Just cast it back to an unsigned char:
std::cout << "result " << static_cast<unsigned char>(value << shift) << "\n";
Or, use bitwise-AND:
std::cout << "result " << ((value << shift) & 0xFF) << "\n";
You could mask the bits you're interested in:
(value << shift) & 0xff
What you are seeing is a result of integer promotion, and is a part of the language. Imagine you're composing a 16-bit integer from 2 8-bit ones - you wouldn't want to manually promote to a higher width integer to get the high and low bits into the right place, right?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With