通过负数计算右移不仅是未定义的,而是在clang [复制]中从一对多映射

问题描述 投票:2回答:2

这个问题在这里已有答案:

当我编译这个C代码并在我的机器上运行十几次时,我每次都得到一个不同的9位负数。另一台机器上的另一个clang编译器产生10位不同的正整数。我期待一个奇怪的值,因为右移由负计数未定义,但我很惊讶该值不是一个唯一的数字。相反,我使用相同的输入获得多个值。为什么这不是数学函数?

#include <stdio.h>
int main(void) {
  printf("%d", 1 >>  -1);
  return 0;
}
c one-to-many undefined-behavior
2个回答
5
投票

因为没有定义行为,所以编译器(在Clang的情况下,至少见下文)选择不在寄存器中放置任何参数将传递给printf。这导致寄存器具有准备C环境并调用main的启动代码留下的任何值。这恰好是在启动期间使用的一些地址,并且它被用于阻止对软件的攻击的Address Space Layout Randomization随机化。

对clang生成的程序集的检查确认没有值放在将用于此参数的寄存器%esi中(使用带有clang-1000.11.45.5的Apple LLVM 10.0.0,为macOS 10.14.3中的默认目标构建)只有开关-O3)。

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


2
投票

当您调用未定义的行为时,允许编译器执行它想要的任何操作。它允许段错误,或每次打印零,或者让你的CPU着火。没有什么能真正要求它确定性或每次都给出相同的结果。

在这种情况下,Clang知道未定义的行为发生,所以它只是停止关怀。编译右移指令并不困难 - 因为没有任何义务。它甚至懒得在寄存器中放置任何值,并且预先留下任何在那里发生的值,这是不可预测的并且是有效随机的。

© www.soinside.com 2019 - 2024. All rights reserved.