负数右移不仅是未定义的,而且在clang中从一对多映射

Eug*_*ene 2 c one-to-many undefined-behavior

当我编译此C代码并在计算机上运行12次时,每次都会得到一个不同的9位负数。另一台计算机上的另一个clang编译器产生的10位正整数不同。我期望得到一个奇怪的值,因为向右移动负数是不确定的,但是让我感到惊讶的是该值不是一个唯一的数字。相反,我使用相同的输入获取多个值。为什么这不是数学函数?

#include <stdio.h>
int main(void) {
  printf("%d", 1 >>  -1);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*hil 5

由于未定义行为,因此编译器(至少在Clang中为例,请参见下文)选择不将任何参数放入将传递参数的寄存器中printf。这将导致准备C环境并调用的启动代码在寄存器中留下任何值main。这恰好是启动期间使用的某个地址,并且通过用于阻止对软件的攻击的地址空间布局随机化进行了随机化

检查由clang生成的程序集,确认没有在该值%esi的寄存器中放置任何值(使用Apple LLVM 10.0.0和clang-1000.11.45.5,在macOS 10.14.3中构建其默认目标)仅带开关-O3)。

当然,其他编译器的行为可能有所不同,因为该行为不是C标准定义的;这仅解释了OP在有限情况下报告的观察结果。