cuvidk cuvidk - 2 months ago 10
C Question

Unexpected result after chaining bit-shift operators in C

I can't figure out why chaining bit-shift operations is not returning the same result as not chaining them.

#include <stdio.h>

void bit_manip_func(unsigned char byte)
{
unsigned char chain = (((byte >> 3) << 7) >> 3);
printf("%d\n", chain); //this prints 144

unsigned char o1 = byte >> 3;
unsigned char o2 = o1 << 7;
unsigned char o3 = o2 >> 3;
printf("%d\n", o3); //this prints 16 as expected
}

int main()
{
//expecting both printf's to print
//the same value (16).
bit_manip_func(73);
return 0;
}


I'm expecting both
printf
calls to print out 16 since 73 in binary is 0100 1001. After applying
byte >> 3
I should get 0000 1001, after
(byte >> 3) << 7
the result should be 1000 0000, and after
(((byte >> 3) << 7) >> 3)
the result should be 0001 0000, which of course is 16. What's actually happening?

Answer

The operators >> and << perform integer promotions on their operands. Thus the type unsigned char is promoted to int, when used with either operator.

In the following line, the variable byte is promoted to type int, and then all three operations are performed on this type:

unsigned char chain = (((byte >> 3) << 7) >> 3);

The left most bit set to one is thus preserved:

01001001 => 01001 => 010010000000 => 010010000 
 ^           ^        ^               ^

In the following code, the variables are promoted to type int, but after each operation, the result, which has the type int, is assigned to an unsigned char and thus wraps (most significant bits are removed),
since the range of unsigned char is [ 0 , 2^8-1 ] on your platform.

unsigned char o1 = byte >> 3;
unsigned char o2 = o1 << 7;
unsigned char o3 = o2 >> 3;

This means that the left most bit set to one is not preserved:

01001001 => 01001 => 10000000 => 000010000
 ^           ^