I recently noticed a (weird) behavior when I conducted operations using shift >>
<<
!
To explain it, let me write this small runnable code that does two operations which are supposed to be identical(In my understanding), but I'm surprised with different results!
#include <stdio.h> int main(void) { unsigned char a=0x05, b=0x05; // first operation a = ((a<<7)>>7); // second operation b <<= 7; b >>= 7; printf("a=%X b=%X\n", a, b); return 0; }
When ran, a = 5
and b = 1
. I expect them both to be equal to 1! Can someone kindly explain why I got such a result?
P.S: In my environment the size of unsigned char
is 1 byte
Left Shift and Right Shift Operators in C/C++ Takes two numbers, left shifts the bits of the first operand, the second operand decides the number of places to shift.
A shift operator performs bit manipulation on data by shifting the bits of its first operand right or left. The next table summarizes the shift operators available in the Java programming language. Each operator shifts the bits of the first operand over by the number of positions indicated by the second operand.
In mathematics, and in particular functional analysis, the shift operator also known as translation operator is an operator that takes a function x ↦ f(x) to its translation x ↦ f(x + a). In time series analysis, the shift operator is called the lag operator.
Use of the Left Shift Operator in C It does so by adding zeros to the right side of the value in the empty spaces that get created due to shifting. It shifts the bits available for the first operand to the left on the basis of the number of positions that the second operand specifies.
In the first example:
a
is converted to an int
, shifted left, then right and then converted back to usigned char
. This will result to a=5
obviously.
In the second example:
b
is converted to int
, shifted left, then converted back to unsigned char
.b
is converted to int
, shifted right, then converted back to unsigned char
.The difference is that you lose information in the second example during the conversion to unsigned char
Detailed explanation of the things going on between the lines:
Case a:
a = ((a<<7)>>7);
, a<<7
is evaluated first.int
. int
.a
gets promoted to type int
, still containing the value 0x05. The 7
literal was already of type int
so it doesn't get promoted.int
by 7, you get 0x0280. The result of the operation is of type int
.int
is a signed type, so had you kept shifting data further, into the sign bits, you would have invoked undefined behavior. Similarly, had either the left or the right operand been a negative value, you would also invoke undefined behavior.0x280 >> 7;
. No promotions take place for the next shift operation, since both operands are already int. Case b:
b <<= 7;
is equivalent to b = b << 7;
.b
gets promoted to an int
. The result will again be 0x0280.0x80
.b
again gets promoted to an int, containing 0x80.Good advice:
stdint.h
rather than the primitive default types in C.A better, safer way to write your program would have been:
#include <stdio.h> #include <stdint.h> int main(void) { uint8_t a=0x05; uint8_t b=0x05; uint32_t tmp; // first operation tmp = (uint32_t)a << 7; tmp = tmp >> 7; a = (uint8_t)tmp; // second operation tmp = (uint32_t)b << 7; tmp = tmp >> 7; b = (uint8_t)tmp; printf("a=%X b=%X\n", a, b); return 0; }
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