2

I made this small program just to get an idea of how to do logical shifting right in C.

#include <stdio.h>

int main (void)
{
    int n=-2,t;
    t = (int)((unsigned int)n >> 1);
    printf("%d\n",t);
    return 0;
}

However, it outputs
2147283747. Am I missing something here? Shouldn't the answer be 7?

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
user3778242
  • 183
  • 1
  • 3
  • 11
  • 6
    What makes you think that? -2 will be something like 0xfffffffe, how would shifting that right by one place possibly equal 7? – John3136 Jul 01 '14 at 05:30
  • I am doing logical shifting. Therefore, on shifting right, a '0' will be appended at MSB giving, 0111. Isn't the decimal value for this equal to 7? – user3778242 Jul 01 '14 at 05:40
  • giving 01111111111111111111111111111, not 0111 ! You have 32-bit `int`s. – M.M Jul 01 '14 at 05:41
  • 0111 is only 4 bits, so even if you were working with "8 bit ints" you'd still have 0111 1111 (127), not 7. – John3136 Jul 01 '14 at 05:44
  • A very good explanation of the differences between `logical` and `arithmetic` shifts can be found at [Bitwise Operations](https://en.wikipedia.org/wiki/Bitwise_operation) – David C. Rankin Jul 01 '14 at 05:44
  • Got it, so I guess this is the correct answer. But just had a small doubt, this means that if I use the shift right operator for doing a logical shift, it won't give the result as division by 2 right? ( As opposed to an arithmetic shift ). – user3778242 Jul 01 '14 at 05:46
  • It will indeed give the same result as division by 2. Assuming you use unsigned types. If you use signed types and the number is negative, then what will happen is implementation-defined. The compiler could implement it as arithmetic shift, or as logical shift, or as something else. – Lundin Jul 01 '14 at 06:35

1 Answers1

7

In C, right-shift of non-negative integral values (either any value of an unsigned type, or any non-negative value of a signed type) is defined as integer division by 2.

Conversion from negative values of int to unsigned int is also well-defined: n wraps around modulo UINT_MAX+1. On typical systems with 32-bit int, UINT_MAX == 4294967295.

So (unsigned int)n is 4294967294. Perform the right-shift on this is division by 2, giving 2147483647. Since that is a valid int, the conversion to int leaves the value unchanged and this should be what you see.

I presume that your 2147283747 is a typo for 2147483647 ?

M.M
  • 138,810
  • 21
  • 208
  • 365
  • My bad. Yes it is, but then how can I perform a logical shift right in C. While going through the links here, I used the same method. as: http://stackoverflow.com/questions/5253194/implementing-logical-right-shift-in-c – user3778242 Jul 01 '14 at 05:38
  • I'm not sure what you mean. This is a logical right shift, and the result of shifting `0xFFFFFFFE` is unsurprisingly `0x7FFFFFFF`. – M.M Jul 01 '14 at 05:39
  • Yes, this shows lack of skills on my part that I wasn't able to convey the idea properly. What I am trying to do is, I have a negative number -2. Now, if I simply use the right shift operator, it will do an arithmetic shift giving out -1 which is correct. However, how do I acheive, a logical right shift on this number? – user3778242 Jul 01 '14 at 05:41
  • @user please define logical shift – David Heffernan Jul 01 '14 at 05:46
  • In case of logical right shift, a '0' will be put at MSB irrespective of the value of the sign bit. – user3778242 Jul 01 '14 at 05:47
  • In case of logical right shift, it wont be simply divide by 2, right? – user3778242 Jul 01 '14 at 05:47
  • "Logical right shift" and "divide by 2, discarding remainder" mean the same thing for positive numbers. If you are using the term "logical" then you are applying to a collection of bits with no interpretation; C types provide an interpretation of a collection of bits. When you write `(unsigned int)n` you are specifying that the shift will be logical. – M.M Jul 01 '14 at 05:51
  • I am asking for negative numbers, logical shift right wont be just divide by 2 right as opposed to arithmetic shift right? – user3778242 Jul 01 '14 at 05:52
  • For negative numbers, `>>` is implementation-defined (i.e. it could either be a logical shift or an arithmetic shift, or something else). The division by 2 definition is only for non-negative numbers. However, `(unsigned int)n` is not a negative number. – M.M Jul 01 '14 at 05:53
  • Oh! If I print the value of n after doing `(unsigned int)n` after executing this command, what will it be? It is coming out to be -2 only. Why is that? – user3778242 Jul 01 '14 at 05:56
  • Converting `unsigned int` back to `int` is implementation-defined if the value is larger than `INT_MAX`, however on modern hardware, all compilers define it as the `int` with the same bit-pattern. So you get back what you started with. – M.M Jul 01 '14 at 05:59
  • Make sure you use the right format specifiers , i.e. `%d` for `int` and `%u` for `unsigned int`. Mismatching this causes undefined behaviour. – M.M Jul 01 '14 at 06:00
  • I used %u and it shows again that very large value. 4294967294. Is it because again its converted to that value with all 1's in 32 positions? – user3778242 Jul 01 '14 at 06:12
  • The result of converting `-2` to unsigned int is `4294967294`, which is all 1's except a rightmost 0. (In 2's complement this is also the representation of -2) – M.M Jul 01 '14 at 06:14