位移位和赋值

Bit shifting and assignment

本文关键字:赋值      更新时间:2023-10-16

这简直要把我逼疯了。

int a = 0xffffffff;
int b = 32;
cout << (a << b) << "n";
cout << (0xffffffff << 32) << "n";

输出是

-1
0

为什么我没有得到

0
0

当您移动一个值的位数不小于其大小(例如,对于32位整数,32位或更多位)时,会发生未定义行为。您刚刚遇到了一个未定义行为的例子。

简短的回答是,由于您使用的是32位int的实现,因此语言标准规定32位移位是未定义的行为。C标准(第6.5.7节)和c++标准(第5.8节)都规定

如果右操作数的值为负或大于等于提升后的左操作数的宽度,则未定义该行为。

但是如果你想知道为什么:

许多计算机都有一条可以移动寄存器中的值的指令,但是硬件只处理实际需要的移位值。例如,当移动一个32位字时,只需要5位来表示移位值0…因此,硬件可能会忽略高阶位,在*86机器上也是如此(8086除外)。因此,编译器实现可以直接使用该指令,而无需生成额外的代码来检查移位值是否太大,C标准的作者(其中许多代表编译器供应商)规定,移位量较大的结果是未定义的。

你的第一次移位是在运行时执行的,它遇到了这种情况…你的机器只考虑b的低阶5位,它们是0,所以不会发生移位。第二次移位是在编译时完成的,编译器会以不同的方式计算值,并实际进行32位移位。

如果你想移动的量可能大于你要移动的东西的位数,你需要自己检查值的范围。一种可能的方法是

#define LEFT_SHIFT(a, b) ((b) >= CHAR_BIT * sizeof(a)? 0 : (a) << (b))

c++标准规定::如果右操作数的值为负或大于或等于提升后的左操作数的宽度,则未定义该行为。由于GCC没有选项来处理负的量或可预测的类型宽度之外的量或捕获它们;它们总是被视为未定义的。所以行为没有定义