-3

In the following code when I arithmetically right shift MSB3 (which happens to be 0) by 31 I get 2.

But when I replace MSB3 by 0 I get 0, which is the result I was expecting in the first case.

Why does this happen?

    const int value = 0;  //This happens after adding 0x80000000 to 0x80000000
    const int mask = 0x1;
    const int mask2 = mask << 31;
    const int MSB3 = value & mask2; // MSB3 = 0
    const int trueMSB3 = (MSB3 >> 31) // This gives 2 rather than 0???
    const int trueMSB3 = (0 >> 31) //Gives 0
LucasNesk
  • 183
  • 8
fYre
  • 1,212
  • 3
  • 11
  • 16

1 Answers1

2

If you have 64-bit ints then this is not possible as you have described it; since shifting 0 always gives 0. The "real code" must be different to what you have posted.

If you have 32-bit int then your program already caused undefined behaviour by doing mask << 31. Shifting into the sign bit causes UB. The result of this is that anything can happen; including subsequent code printing 2, or missiles being launched.

Your first comment indicates that maybe the "real code" did not have const int value = 0;, but some other code which you describe. It would be better to post the real code. That code may also have undefined behaviour, judging by your description.

To get well-defined results when doing shifts, use unsigned integers instead. To get better help, update your posted code to be a MCVE and include which compiler and system you are on.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • I am using a 64 bit computer, but integers in C are defined as 4(bytes) 32 bits. Also, why would mask << 31 be undefined? I am assuming you would get 0x80000000, which is what I wanted... – fYre Sep 17 '14 at 02:52
  • It's undefined because the C standard says it is undefined. The C standard says it is undefined because C is supported on a wide range of hardware, some of which do not natively support that operation (and in any case you can easily achieve your goal by using unsigned ints). – M.M Sep 17 '14 at 02:57
  • I thought shifting by the number of bits or more was undefined? Also I got 0x80000000, which was what I was expected – fYre Sep 17 '14 at 03:11
  • 1
    Shifting into the sign bit is undefined (left-shift is defined as multiplying by 2, and if the multiplication would have exceeded `INT_MAX` then it is integer overflow). "Undefined" means there is no standard behaviour and your compiler is within its rights to ignore it or take any other action. Sometimes it might decide to take an action that you expected – M.M Sep 17 '14 at 03:13
  • @fYre wants an arithmetic right shift, so suggesting unsigned isn't super halpeful :/. You can't reliably ask for that in C, implementations are allowed to give you a logical right shift for `>>` on signed `int` (which is total crap, IMO, too weak a standard for its own good). But for broadcasting a bit to all bit-positions, you can do `(x<0) : ~0UL : 0UL` and compilers will turn that into a `sar` or `asr` or whatever it's called on the target machine. As a bonus, it doesn't depend on 2's complement anymore. – Peter Cordes Apr 15 '19 at 13:03
  • @CacahueteFrito: Did you mean arithmetic? No, division has different rounding semantics for negative inputs than arithmetic right shift. `-5 >> 1 = -3` for 2's complement arithmetic right shift, rounding towards -Inf, but -5/2` truncates towards 0, giving `-2` with remainder `-1`. Plus, `>>31` isn't expressible with a 32-bit integer divisor. Writing `/2` in C for a signed integer forces the compiler to emit multiple instructions that properly implement rounding semantics on top of shifts, unless it can prove negative dividends are impossible. – Peter Cordes Apr 15 '19 at 13:32