Left Shift and Right Shift Operators in C
Bitwise operations play a crucial role in low-level programming by enabling the manipulation of individual bits within binary data. Among these operations, the left shift and right shift operators are fundamental tools with a wide range of applications for binary data manipulation.
In the realm of C programming, we will delve into these operators to understand their mechanics, explore their practical applications, and grasp their significance in real-world scenarios.
Understanding Bitwise Not Operator
The left shift operator and right shift operator for bitwise shifts in C are denoted by “” and “>>,” respectively. These operators allow us to change the value of a number based on the altered places by shifting the bits of a number to the left or to the right.
Left Shift Operator (<<)
The value to be shifted and how many positions to be added to it are the two operands for the left shift operator (). By the predetermined number of locations, it shifts the bits to the left while packing zeros into the empty spaces on the right. Here is an illustration:
#include <stdio.h>
int main() {
int a = 5; // Binary: 0101
int result = a << 2; // Binary result: 010100 (20 in decimal)
printf("Result of a << 2: %d\n", result); // Output: 20
return 0;
}Output:
#include <stdio.h>
int main() {
// Declare a local variable
unsigned int value = 15; // Decimal value
// Use the left shift operator to shift the bits
value = value << 2; // Left shifting by 2 positions
printf("After left shifting by 2 positions, the updated value is: %u\n", value);
return 0;
}Output:
After left shifting by 2 positions, the updated value is 60
Time Complexity: O(1)
Space Complexity: O(1)
How Left Shift Operator Works in C?
Two integral operands are subjected to a bitwise operation by the left shift () operator in the C language. The second operand specifies a number of locations in which the operator should shift the bits of the first operand to the left. Zeros are inserted into the empty spaces left by the shift on the right side. The sign bit and the bits that are relocated past the end are discarded.
Key points to understand:
- Operand Types: Both operands of the left shift operator should be of integral types, typically integers.
- Shifting Procedure: The binary form of the initial operand is moved towards the left by the quantity of positions indicated by the second operand.
- Zero Fill: The newly created positions on the right (least significant side) are filled with zeroes.
- Discarding Shifted Bits: Bits shifted beyond the left end are discarded, including the sign bit.
Undefined behavior arises in the following cases:
- If the first operand is negative, the outcome is undefined.
- If the second operand is negative or greater than or equal to the number of bits in the first operand, the outcome is undefined.
- If the second operand is greater than the size of the integer type, the result is undefined.
Let’s consider the decimal number 12, which has a binary representation of 1100. If we apply the left shift operator by 2 positions, denoted as 12 << 2, the following steps occur:
- The binary value 1100 (decimal 12) is taken.
- Each bit is shifted to two positions to the left.
- The result is 110000, which is 48 in decimal.
So, 12 << 2 results in 48. This can be explained as shifting the number 12 to the left by two positions, effectively multiplying it by 2^2 or 4, which gives 48.
Right Shift Operator (>>)
Similar to the left shift, the right shift operator (>>) shifts the bits to the right. The value to be shifted and the number of positions to shift it by are also required as operands. Here’s an illustration:
#include <stdio.h>
int main() {
int a = 20; // Binary: 10100
int result = a >> 2; // Binary result: 00101 (5 in decimal)
printf("Result of a >> 2: %d\n", result); // Output: 5
return 0;
}Output:
#include <stdio.h>
int main() {
// Declare a local variable
unsigned int value = 0x3E; // Hexadecimal equivalent of 62 in decimal
value = value >> 3; // Right shifting by 3 positions
// Print the new value of the variable
printf("The new value = %u\n", value);
return 0;
}Output:
After right shifting by 3 positions, the updated value is 7
Time Complexity: O(1)
Space Complexity: O(1)
How Right Shift Operator Works in C?
In C, the right shift (>>) operator is a bitwise operation that enables the right-bit shifting of integral data types. It uses two operands, the value to be shifted (left operand) and the number of positions to shift by (right operand), much like the left shift operator. The left operand’s binary representation shifts the specified number of positions to the right during this operation, essentially dividing the value by 2, raised to the power of the shift count.
Example:
Consider the decimal number 48, which in binary is 110000. If we apply the right shift operator by 2 positions, denoted as 48 >> 2,
the following steps occur:
- The binary value 110000 (decimal 48) is taken.
- Each bit is shifted to two positions to the right.
- The result is 001100, which is 12 in decimal.
So, 48 >> 2 results in 12. This can be understood as shifting the number 48 to the right by two positions, effectively dividing it by 2^2 or 4, which gives 12.
It’s important to note that while the right shift operator is useful for bit manipulation and division by powers of 2, there are scenarios where its behavior becomes undefined:
- If the value of the first operand is negative, the result of the right shift operation is undefined.
- Similarly, if the value of the second operand is negative or if it’s greater than or equal to the number of bits in the first operand, the result is undefined.
Important Points
Caution should be exercised when employing left-shift and right-shift operators with negative numbers. If either of the operands is negative, the outcome becomes unpredictable. For instance, both -2 >> 1 and -2 << 1 yield undefined behavior.
#include <stdio.h>
int main() {
int negativeNumber = -2;
int resultLeft = negativeNumber << 1; // Undefined behavior
int resultRight = negativeNumber >> 1; // Undefined behavior
printf("Left Shift: %d\n", resultLeft);
printf("Right Shift: %d\n", resultRight);
return 0;
}Output:
Left Shift: -4
Right Shift: -1
When shifting a number by an amount exceeding the bit size of the integer, the results enter into uncertain territory. For instance, attempting 5 << 40 without considering the 32-bit limitation could lead to undefined outcomes. To handle such cases with larger values, like 10ULL << 60, the suffix ULL signifies Unsigned Long Long, utilizing its 64-bit capacity to accommodate substantial values.
#include <stdio.h>
int main() {
int number = 5;
int result = number << 40; // Undefined behavior for 32-bit integers
printf("Shift Result: %d\n", result);
return 0;
}Output:
Shift Result: 0
Left-shifting a number by 1 and right-shifting it by 1 is akin to multiplying the original value by 2 raised to the given exponent (e.g., 3 << 2 equals 3 * 2^2) and dividing the initial value by the second value raised to the power of 2 (e.g., 8 >> 2 equals 8 / 2^2), respectively.
#include <stdio.h>
int main() {
int value = 3;
int leftShiftResult = value << 2; // Equivalent to 3 * 2^2
int rightShiftResult = value >> 2; // Equivalent to 3 / 2^2
printf("Left Shift Result: %d\n", leftShiftResult);
printf("Right Shift Result: %d\n", rightShiftResult);
return 0;
}Output:
Left Shift Result: 12
Right Shift Result: 0
Logical vs. Arithmetic Shift
The difference between logical right shift and arithmetic right shift must be understood. During an arithmetic right shift, the sign bit (located at the leftmost side) is copied to ensure the number’s sign remains unchanged. On the other hand, in a logical right shift, the vacant bit slots are filled with zeros. The majority of C compilers employ arithmetic right shift.
Applications of Shift Operators
Shift operators find numerous applications in programming:
- Bit Manipulation: Shifting is used to isolate and modify specific bits within a number.
- Optimization: Shifting by powers of 2 is more efficient than multiplication or division.
- Encoding and Decoding: Used in protocols like UTF-8 for efficient data representation.
Considerations and Pitfalls
Be cautious with shifting beyond the data type’s width or by a negative amount, as it results in undefined behavior. Additionally, make sure to use the appropriate shift operator based on your requirements.
Performance and Efficiency
Shift operations are generally faster and more efficient than traditional multiplication or division, especially when working with powers of 2. Modern compilers often optimize these operations.
Conclusion
Learning the left shift and right shift operators will give you the ability to execute complex bit manipulations and optimize your code as you enter the world of low-level programming. Despite having a straightforward notion, these operators are crucial for performing complex programming tasks. You can expand the efficiency and accuracy of your C programming by utilizing their skills.
We work very hard to provide you quality material
Could you take 15 seconds and share your happy experience on Google





