Right Shift in the C language

This will be a short post that is comprised of one part educational information and one part rant. The inspiration for this post originates from a very common component in technical interview questions surrounding bit manipulation, The right shift operation.

An example interview question might look something like this.

1
2
3
4
5
6
7
int main() {

    int16_t num = 0x0FFF;
    num = num << 4;
    num = num >> 4;
    printf("%" PRId16 , num);
}

The questions is, what is printed in the printf statement?

What this questions is looking for is if you have knowledge of arithmetic vs logical right shift operations.  Let's go through what the interviewer wants you to notice and then we'll look at why that isn't quite true.

Whats happening here is that:

First we assign the value 0x0FFF hex to a signed 16 bit integer. This can also be represented in binary as 0000 1111 1111 1111. 
We then shift the 16 bit integer 4 times to the left which gives us the value 0xFFF0 or alternatively 1111 1111 1111 0000 in binary. 
We would expect that because we are performing a right shift operation on a signed number that we would perform an arithmetic shift. This means that we would shift a 1 into the most significant bit place.
So now num should equal 0xFFFF or 1111 1111 1111 1111. 
The last line simply prints the result. 

If you told an interviewer this they would probably be happy with your answer. This is, in fact, what they were most likely expecting as an answer. Unfortunately the true answer to this question is "We have no way of knowing with the given information."

The truth is that the right shift operation is implementation dependent. You are at the mercy of the creators of whichever compiler you're using.

Don't believe me? It's written plain as day in the C11 ISO standard.

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2 . If E1 has a signed type and a negative value, the resulting value is implementation-defined.
This can be found in section 6.5.7 Bitwise shift operators, depending on what version of the standard you're reading.

No comments:

Post a Comment