2

When I compile this C code and run it a dozen times on my machine, I get a different 9 digit negative number each time. Another clang compiler on another machine yields 10 digit positive integers that are different. I am expecting a strange value because right shifting by a negative count is undefined, but I am surprised that the value is not a single, unique number. Instead, I am get multiple values with the same input. Why is this not a mathematical function?

#include <stdio.h>
int main(void) {
  printf("%d", 1 >>  -1);
  return 0;
}
Eugene
  • 89
  • 3

2 Answers2

5

Because the behavior is not defined, the compiler (in a case of Clang, at least, see below) chooses not to put anything in the register where the argument would be passed to printf. This results in the register having whatever value was left there by the start-up code that prepares the C environment and calls main. This happens to be some address used during start-up, and it is randomized by the Address Space Layout Randomization used to impede attacks on software.

Examination of the assembly generated by clang confirms no value is placed in the register, %esi, that would be used for this argument (using Apple LLVM 10.0.0 with clang-1000.11.45.5, building for its default target in macOS 10.14.3 with only the switch -O3).

Other compilers may behave differently, of course, since the behavior is not defined by the C standard; this merely explains the observations reported by the OP in limited cases.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    Argh, finished examining the assembly output and came back to find your answer had gotten in first! +1 regardless, as this is entirely right. – Draconis Mar 08 '19 at 04:20
  • 1
    @Draconis Ill thumbs up you bro, hate when that happens to me, also thumbed Eric. – Bwebb Mar 08 '19 at 04:21
2

When you invoke undefined behavior, the compiler is allowed to do absolutely anything it wants. It's allowed to segfault, or print zero every time, or set your CPU on fire. Nothing really requires it to be deterministic or give the same result every time.

In this case, Clang knows that undefined behavior happens, so it just stops caring. It doesn't bother to compile a right-shift instruction—because nothing obligates it to. It doesn't even bother to put any value in the register, and leaves whatever value happened to be in there beforehand, which is unpredictable and effectively random.

Draconis
  • 3,209
  • 1
  • 19
  • 31