poopdealer43
poopdealer43

Reputation: 9

Confusion about using bitwise operators in c

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

Answers (3)

mortytheplatypus
mortytheplatypus

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

ikegami
ikegami

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.

Logical shift right

With signed integers, >> performs an arithmetic shift right. An arithmetic shift right shifts in the sign bit.

Arithmetic shift right

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

dbush
dbush

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

Related Questions