77

What exactly happens here?

a << -5

Obviously it doesn't right shift. But the book I'm reading states:

On one machine, this expression actually does a left shift of 27 bits

My question is; why? What causes a left shift of 27 bits? And what exactly happens when shifting with a negative shift count? Thank you.

Ishq
  • 1,189
  • 1
  • 8
  • 10
  • 2
    Note that the behavior is actually undefined behavior, you can't rely on it operates modulo 32. [For example](https://tio.run/##Sy4o0E1PTv7/XzkzLzmnNCXVprgkJTNfL8OOKzOvRCE3MTNPQ7MazE6tKLDVNbHmKigC8tI0lFRTYvKUdIyNbGyAMprYxDWAApq6JkC52v//AQ). – user202729 Mar 26 '18 at 06:14

5 Answers5

86

Negative integers on right-hand side is undefined behavior in the C language.

ISO 9899:2011 6.5.7 Bit-wise shift operators:

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 32
    Btw if your book didn't mention that this is undefined behavior, you should consider getting another book. – Lundin Feb 09 '11 at 13:54
  • 2
    Depending on what else the book said, you could argue this is exactly what it was saying (though it could stand to be clearer). "On one machine, something happens" implicitly means it might not happen on others. – 3Doubloons Feb 17 '11 at 03:57
  • If this does not work, would it be some operation that would have equivalent behavior to the wanted behavior in the question? Seems kind of sad to have write an equation for this particular operation :(. I try to do a right shift that makes 1 to be 0. – patrik Feb 11 '15 at 15:46
  • What is the rationale for undefined instead of implementation defined here? E.g. does some major architecture raise exceptions? – Ciro Santilli OurBigBook.com May 26 '15 at 10:11
  • @CiroSantilli六四事件法轮功 It is just that negative shift doesn't make sense. Just what is "shift negative"? Is it a right shift? Is it a shift by the binary value of the right operand, ie a two's complement value converted to some large nonsense value? CPU architectures that have a "logical left shift x bits" instruction define this number as unsigned. For example ARM LSL instruction: "Rs Specifies the register holding the shift length to apply to the value in Rm. Only the least significant byte is used and can be in the range 0 to 255." Alternatively you can write a number #n from 0 to 31. – Lundin May 26 '15 at 11:49
  • @Lundin in that case why not just cast to unsigned, and make it implementation defined like cast to unsigned, which is much less drastic than UB? I was under the impression that most UB came from CPU exceptions. But reading better there is also optimization involved which might explain it here: http://stackoverflow.com/questions/19490240/does-cast-between-signed-and-unsigned-int-maintain-exact-bit-pattern-of-variable and http://stackoverflow.com/questions/11962457/why-is-using-an-uninitialized-variable-undefined-behavior-in-c – Ciro Santilli OurBigBook.com May 26 '15 at 12:46
  • 2
    @CiroSantilli六四事件法轮功 A lot of undefined behavior comes from shortcomings of the C standard committee, rather than some sound rationale about hardware limitations. But in this case I don't really see much room for improvement: if the standard forced a promotion of the right operand to unsigned type, you would still end up with something like `a << (unsigned int)-5` which would mean `a << 0xFFFFFFFB`, which is also UB by the cited text above. – Lundin May 26 '15 at 13:12
  • @3Doubloons "Undefined behavior" has a precise meaning which is far more serious than "implementation dependent". See for example https://randomascii.wordpress.com/2014/05/19/undefined-behavior-can-format-your-drive/ – Don Hatch Feb 24 '16 at 06:04
21

As already answered by other members, it produces undefined behavior. What I would like to mention here is that you quote from the book ( "On one machine" ) seems to be partial. It does not generalize the behavior. The book might also have explained that the behavior is undefined as per the standard. BTW, I was just going through "The New C Standard - An Economic and Cultural Commentary" and found this statement :

The Intel Pentium SAL instruction (generated by both gcc and Microsoft C++ to evaluate left-shifts) only uses the bottom five bits of the shift amount

This very well explains why a left shift of -5 could result into a left shift of 27 ( for 2's complement representation of negative numbers )

Anand
  • 473
  • 3
  • 14
  • 4
    I am sure that the "On one machine" sentence in the OP's book only serves as an example, right after stating that this is undefined. It's actually one of the nice examples that "undefined" really means anything, and not just "clean" abrupt termination of the executing program. If used this way, it wouldn't make sense to give the impression that the left shift by 27 is something you have a right to expect. – Pascal Cuoq Feb 09 '11 at 17:05
  • +1 for answering the part of the question "what exactly happens [on the quoted "one machine"] when shifting with a negative shift count". sure, UB is UB, and so we shouldn't assume anything about it, but this explanation is extremely illustrative of the kind of perils that led them to _make_ it UB. (my brain always wants to say 'but why can't it be defined for literal integers', but then i think more and realise that's absurd ;-) – underscore_d May 30 '16 at 19:51
11

The behaviour is undefined.

In 5-bit binary arithmetic, two's-complement -5 has the same binary representation as unsigned +27, which probably explains that particular platform.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
0

If the value you're shifting is a 32 bit variable, shifting -5 goes in a "loop" and shifts 27 forward. Shifting can only take place in a "unsigned" fashion.

arnorhs
  • 10,383
  • 2
  • 35
  • 38
  • 1
    But if the 32 bit variable is signed, the integer promotions won't change the signedness of -5. And then the behavior is undefined and the program is free to halt and catch fire. – Lundin Feb 09 '11 at 13:57
  • probably. Anyways I think it's a bad practice :) – arnorhs Feb 09 '11 at 14:10
-3
int main()
{
    unsigned int a = 1;
    printf("%u\n",a<<(-1));
    return 0;
}

The output is 2147483648.

Here is my assumption and validation:(just assumption!)

1.The "<<" right operand must be unsigned int type,

so firstly, the (int) “-1” will be cast into (unsigned int) "-1". Cause int type is two's-complement representation, the result will be 2^32-1(unsigned int)

2.Due to number 2^32-1 is larger than the Max displacement digit, 2^32 - 1 will be mod 32, which equals 27

I also tried some other nagetive right operand numbers, and the manual calculation results with assumpted rules will be the same with what product by my IDE.

I am trying to find some supporting offical documents, witch could verificate whether my assumption is right or not. Maybe you can tell me.

Wu Little
  • 11
  • 1