C++: Bitwise Shift Operators

Bitwise Shift Operators

In this C++ video tutorial, we demonstrate how to use the bitwise shift operators. To begin, we first must understand binary number representations. The binary format is how a computer stores numbers using only 0s and 1s for digits. To help understand this, we illustrate the decimal and binary representations of the number 237 in the image below.

The decimal representation is how we normally represent numbers. Each digit in decimal is in the range 0-9 and is multiplied by a power of 10. In binary, each digit is either 0 or 1 and is a multiple of a power or 2, as shown. For convenience, the name "binary digit" is shortened to bit.

In C++, we have four basic unsigned integer types, as shown in the image above. These types are unsigned char, unsigned short, unsigned int, and unsigned long long. They have 8, 16, 32, and 64 bits each, respectively. With more bits, we can represent a larger range of numbers.

In addition to the unsigned integer types, we have four corresponding basic signed integer types, char, short, int, and long long. These four types use half of their range to represent negative numbers. They do this through a scheme called the two's complement representation. Essentially, the two's complement representation takes the most significant bit and assigns it the negative of its normal unsigned value. In the program below, we use the signed int type to illustrate this.

#include <iostream>

void PrintBinaryAndDecimal(int iMyNumber) {
	using namespace std;
	cout << "Bin = ";
	for (int i = 31; i >= 0; --i) {
		std::cout << (((iMyNumber >> i) % 2) ? '1' : '0');
	}
	cout << " : Dec = " << iMyNumber << endl << endl;
}

int main() {
	using namespace std;

	int iMyNumber = -38;

	cout << "Original:" << endl;
	PrintBinaryAndDecimal(iMyNumber);

	cout << "Left-shifted:" << endl;
	PrintBinaryAndDecimal(iMyNumber << 1);

	cout << "Right-shifted:" << endl;
	PrintBinaryAndDecimal(iMyNumber >> 1);

	// Keep the window open
	cin.get();
	return 0;
}

In this program, we create an int and assign it the value -38. Then we apply the shift operators to shift it left and right by 1 in each direction. The output of the program is shown below.

There are some interesting things to note about the output. First, the left-shifted number is twice the original value, while the right-shifted number is half of the original value. Second, the left shift shifts in a 0 on the right side, while the right shift shifts in a 1 on the left side. For unsigned types, a 0 is always shifted in. However, the signed types must shift in a bit that is the same as the sign bit for right shifts to preserve the halving property of the shift.

We conclude with some final observations. Although the program above only shifted by a single bit at a time, we can shift by any number of bits in the range from 0 to one less than the number of bits in the integer type (up to 31 in the 32 bit example above). Also, we may lose data by shifting out signifcant bits of data: this is called overflow for left shifts and truncation for right shifts. In either case, data will be lost and we may even change the sign of a signed integer type, if the sign bit is changed.