According to C++03, 5.8/2, left-shifting is defined as follows:
The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 multiplied by the quantity 2 raised to the power E2, reduced modulo ULONG_MAX+1 if E1 has type unsigned long, UINT_MAX+1 otherwise.
What bothers me here is that unsigned types are explicitly mentioned yet signed types are ignored completely. Compare this to 5.8/3 which defines right-shifting:
The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
In 5.8/3 both signed and unsigned are explicitly mentioned, even signed holding non-negative and signed holding negative values are mentioned separately.
AFAIK when something is not explicitly defined in C++ Standard the behavior is undefined. I've also seen this question, but it focuses on differences between C and C++ and doesn't seem to have an answer everyone would agree upon.
Is left-shifting a signed integer defined in C++03?
5.8/2 says that it interprets it as a bit-pattern, which is only implementation dependent if for some reason your implementation doesn't use 2's complement, or if your compiler second-guesses you (they don't). C++11 is more explicit, but says the same thing.
Signed integers use what's known as 2's complement. Basically if you bit-shift a signed integer by 1, if it's positive and below 2^(bits - 2) it will work as if it were unsigned. If it is above that but positive, you will create a strange negative number that bears no relation to the original. If it is negative to begin with, you'll get possibly a negative, possibly a positive number.
For instance, if we have an 8-bit signed integer representing -1:
11111111 // -1
If we left-shift that we end up with
11111110 // -2
However, let's say we have -120
10001000 // -120
We shall end up with
00010000 // 16
Obviously that is not correct!
Continuing, using number 65:
01000001 // 65
Shifted left, this will become:
10000001 // -127
Which equates to -127.
However, the number 16:
00010000 // 16
Shifted left is
00100000 // 32
As you can see, it "sometimes works, sometimes doesn't" but usually works if your number is below 2^(bits-2) and sometimes but not usually if it is above -(2^(bits-2)). That is, to shift left by 1. To shift left by 2, take another bit off. Etc.
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