0

I am developing a simple C app on a CentOS linux machine my university owns and I am getting very strange inconsistent behavior with the << operator.

Basically I am attempting to shift 0xffffffff left based on a variable shiftNum which is based on variable n

int shiftNum = (32 + (~n + 1));
int shiftedBits = (0xffffffff << shiftNum);

This has the effect of shifting 0xffffffff left 32-n times and works as expected. However when n = 0 and shiftNum = 32 I get some very strange behaviour. Instead of getting the expected 0x00000000 I get 0xffffffff.

For example this script:

int n = 0;
int shiftNum  = (32 + (~n + 1));
int shiftedBits = (0xffffffff << shiftNum );
printf("n: %d\n",n);
printf("shiftNum: 0x%08x\n",shiftNum);
printf("shiftedBits: 0x%08x\n",shiftedBits);
int thirtyTwo = 32;
printf("ThirtyTwo: 0x%08x\n",thirtyTwo);
printf("Test: 0x%08x\n", (0xffffffff << thirtyTwo));

Outputs:

n: 0
shiftNum: 0x00000020
shiftedBits: 0xffffffff
ThirtyTwo: 0x00000020
Test: 0x00000000

I have no idea what is going on honestly. Some crazy low-level something I suspect. Even more strange the operation (0xffffffff << (shiftNum -1)) << 1 outputs 0x00000000.

Does anyone have any clue whats going on?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Samuel Davidson
  • 783
  • 6
  • 16
  • If you are left shifting a signed quantity you may get undefined behaviour. – Weather Vane Sep 05 '15 at 21:59
  • This question has been asked before, http://stackoverflow.com/questions/4009885/arithmetic-bit-shift-on-a-signed-integer and here http://stackoverflow.com/questions/7622/shift-operator-in-c – Weather Vane Sep 05 '15 at 22:01
  • My question is completely about left bit shifting. Those two questions you just linked were about the differences between `<<` and `>>` . I understand that the MSB gets copied when shifting right but that has nothing to do with my question. – Samuel Davidson Sep 05 '15 at 22:06
  • Both questions discuss shifts in both directions. You can't have read past the first sentence. – Weather Vane Sep 05 '15 at 22:06
  • See Jonathan Leffler's answer, just an additional note. It is likely that your compiler here takes the simplest path, just producing an assembly shift instruction with the given count operand as-is. On Intel 32 bits, only the low 5 bits of this count operand is used, so your 32 will essentially turn into a 0, that's how you get 0xFFFFFFFF. Here the undefined behavior so played out this way, on some other system, it may play out in some other way. – Jubatian Sep 24 '15 at 12:46

1 Answers1

1

If you invoke undefined behaviour, the results are unspecified and anything is valid.

When n is 0, 32 + (~n + 1) is 32 (on a two's complement CPU). If sizeof(shiftNum) == 4 (or sizeof(shiftNum) * CHAR_BIT == 32, which usually has the same result), then you are only allowed to shift by values 0..31; anything else is undefined behaviour.

ISO/IEC 9899:2011 §6.5.7 Bitwise shift operators:

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.

The result, therefore, is correct — even if you get a different answer each time you run the code, or recompile the program, or anything else.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278