"C++ runs the world"

Article by Ayman Alheraki in October 8 2024 01:52 PM

In C++, **shift operators** are used for bitwise manipulation of data. These operators allow you to shift the bits of a number to the left or right, effectively multiplying or dividing the number by powers of two. They are commonly used in low-level programming, such as hardware control, cryptography, and optimization.

Shift operators are represented by `<<`

for left shift and `>>`

for right shift.

**Left Shift Operator (**`<<`

)The left shift operator shifts the bits of its left operand to the left by the number of positions specified by its right operand.

Each left shift multiplies the number by 2.

Bits that are shifted beyond the size of the data type are discarded, and the vacant positions are filled with 0.

**Syntax**:`result = number << shift_count;`

**Example**:`using namespace std;`

`int main() {`

`int num = 3; // Binary: 0000 0011`

`int result = num << 1; // Shift bits left by 1`

`cout << "3 << 1 = " << result << endl; // Output: 6 (0000 0110)`

`return 0;`

`}`

**Explanation**:The binary representation of

`3`

is`0000 0011`

.Shifting left by 1 results in

`0000 0110`

, which equals`6`

.

**Right Shift Operator (**`>>`

)The right shift operator shifts the bits of its left operand to the right by the number of positions specified by its right operand.

Each right shift divides the number by 2.

Vacant positions are filled differently based on the data type (signed or unsigned):

**Unsigned integers**: Vacant positions are filled with`0`

.Signed integers

: It depends on the implementation (logical or arithmetic right shift):

*Logical shift*: Vacant positions are filled with`0`

.*Arithmetic shift*: Vacant positions are filled with the sign bit (preserving the number's sign).

**Syntax**:`result = number >> shift_count;`

**Example**:`using namespace std;`

`int main() {`

`int num = 12; // Binary: 0000 1100`

`int result = num >> 2; // Shift bits right by 2`

`cout << "12 >> 2 = " << result << endl; // Output: 3 (0000 0011)`

`return 0;`

`}`

**Explanation**:The binary representation of

`12`

is`0000 1100`

.Shifting right by 2 results in

`0000 0011`

, which equals`3`

.

With the introduction of **Modern C++**, shift operators are primarily used for bitwise operations, especially when manipulating hardware registers or creating efficient low-level algorithms. However, there are a few points to note:

**Integer Promotion and Undefined Behavior**In C++, the right operand of a shift must be non-negative and less than the number of bits in the left operand. Violating this can lead to

**undefined behavior**.Modern C++ provides

`std::clamp()`

and other safeguards to avoid undefined behavior during shifts.

**Use of**`std::bitset`

for Bit ManipulationModern C++ encourages the use of the

`std::bitset`

class for bit manipulation. This provides a safer and more expressive way to manage bits.With

`std::bitset`

, you can easily visualize, manipulate, and manage individual bits without directly working with shift operators.

**Example with**:`std::bitset`

`using namespace std;`

`int main() {`

`bitset<8> bits(3); // Binary: 00000011`

`cout << "Original bits: " << bits << endl;`

`// Shift left`

`bits <<= 1;`

`cout << "After left shift by 1: " << bits << endl;`

`// Shift right`

`bits >>= 2;`

`cout << "After right shift by 2: " << bits << endl;`

`return 0;`

`}`

**Output**:`Original bits: 00000011`

`After left shift by 1: 00000110`

`After right shift by 2: 00000001`

**Safe Shifting with**`std::bitset`

When you use

`std::bitset`

, you are protected against shifting by more than the number of bits in your type, as`std::bitset`

operations are defined and safe.Unlike primitive types,

`std::bitset`

won’t allow undefined behavior from out-of-range shifts.

In C++, shifting signed integers can be tricky because of the difference between **logical** and **arithmetic** shifts.

**Unsigned integers**always use logical shifts:Left shift fills with 0.

Right shift fills with 0.

**Signed integers**may use arithmetic shifts, which preserve the sign bit:Left shift fills with 0.

Right shift fills with the sign bit (for negative numbers).

**Example of Signed Right Shift**:

`using namespace std;`

```
```

`int main() {`

` int num = -8; // Binary (assuming 32-bit): 11111111111111111111111111111000`

` int result = num >> 2; // Arithmetic right shift`

```
```

` cout << "-8 >> 2 = " << result << endl; // Output: -2 (Binary: 11111111111111111111111111111110)`

` return 0;`

`}`

**Efficient Multiplication and Division**:Left shifting multiplies a number by

`2^n`

, while right shifting divides by`2^n`

.

**Example**:`int x = 4;`

`int multiply_by_8 = x << 3; // Multiply by 8 (2^3)`

`int divide_by_4 = x >> 2; // Divide by 4 (2^2)`

**Setting and Clearing Specific Bits**:You can use shift operators to manipulate specific bits in a number, especially in systems programming or embedded development.

**Example: Set the 3rd bit of a number**:`int num = 5; // Binary: 0000 0101`

`num |= (1 << 2); // Set 3rd bit (counting from 0)`

`cout << num; // Output: 7 (Binary: 0000 0111)`

**Bit Masking**:Shift operators are used in combination with bitwise AND/OR to create or manipulate masks for selective bit manipulation.

**Example: Clear the 2nd bit**:`int num = 7; // Binary: 0000 0111`

`num &= ~(1 << 1); // Clear the 2nd bit`

`cout << num; // Output: 5 (Binary: 0000 0101)`

Shift operators (`<<`

and `>>`

) are powerful tools in C++ for manipulating individual bits of a number. They have various practical applications, including optimization, cryptography, and embedded systems development. In Modern C++, while these operators are still relevant, features like `std::bitset`

make bit manipulation more robust and less prone to errors, allowing for safer handling of binary data. Always be cautious of undefined behavior when shifting beyond the bit limits of your types.