Reputation: 9
int example(int x) {
// Example input: x = 0x89ABCDEF
// In binary: 1000 1001 1010 1011 1100 1101 1110 1111
int a = x >> 24; // 0000 0000 0000 0000 0000 0000 1000 1001
int a2 = a & 0xff;
return a;
}
When I run my example code, I expect a = 137. Shifting x to the right by 24 bits should give 0000 0000 0000 0000 0000 0000 1000 1001, which is 137 in decimal form. However, my program returns a = -119.
I made a modification in a2, which gave me the correct result. I don't really understand how a2 is any different from a, and why they output different values. Wouldn't using the & operator with 0xff return the same thing, making a = a2?
Upvotes: 0
Views: 106
Reputation: 11
For the left shift operation, every bit is replaced by the immediate right bit, except the 0-th bit. The 0-th bit gets replaced by 0.
For the right shift operation, every bit is replaced by the immediate left bit, except the last bit.
For right shift of signed values, the sign bit remains constant. If it were 1 before the shift began, it will remain 1 and if it were 0, before the shift began, it will remain 0.
But for right shift of unsigned values, the last bit is replaced by 0.
You passed x = 0x89ABCDEF
as an int
, i.e. signed int
, so, x = 1000 1001 1010 1011 1100 1101 1110 1111
, after 24 signed right shift, becomes x = 1111 1111 1111 1111 1111 1111 1000 1001
which is -119
in decimal.
If you pass x
as an unsigned int
, after 24 unsigned right shift, becomes x = 0000 0000 0000 0000 0000 0000 1000 1001
which is equal to 137
in decimal.
This satisfies your required answer:
int example(unsigned int x) {
return x >> 24;
}
Upvotes: 1
Reputation: 385496
Cast the int
to an unsigned int
to force the use of a logical shift as you expect.
Each shift effectively divides the number by 2. You started with -1,985,229,329, so you ended up with -1,985,229,329 / 224 = -119. This is the correct result, not 137.
Correctly dividing the number is achieved by changing what kind of shifting is performed based on whether it's a signed integer or an unsigned integer.
With unsigned integers, >>
performs a logical shift right. A logical shift right will shift in a zero.
With signed integers, >>
performs an arithmetic shift right. An arithmetic shift right shifts in the sign bit.
You were expecting a logical shift, but got an arithmetic shift. You could get the desired shift by casting the int
to an unsigned int
. Better yet, use an unsigned int
from the start.
Images courtesy of the linked Wikipedia articles.
Upvotes: 2
Reputation: 223689
You're performing a right shift on a signed integer. Assuming 2's complement representation, the value in question is actually negative since the high-order bit is set. Most 2's complement implementations will shift in "1" bits on left if the high bit is set to preserve the sign.
By performing a bitwise-AND with 0xff
, you're setting the upper bytes to all-bits-0.
If the type of x
was unsigned
, that would mean 0's are always shifted in from the left.
Upvotes: 3