赋值时的位移位对变量没有影响

Bitshift on assignment has no effect on the variable

我以为我在 this answer 中找到了类似的东西,但在那种情况下,他们没有将表达式的结果分配给变量。在我的例子中,我正在分配它,但表达式的位移位部分没有效果。

unsigned leftmost1 = ((~0)>>20);
printf("leftmost1 %u\n", leftmost1);

Returns

leftmost1 4294967295

鉴于

unsigned leftmost1 = ~0;
leftmost1 = leftmost1 >> 20;
printf("leftmost1 %u\n", leftmost1);

给我

leftmost1 4095

我希望将逻辑分成两行不会有影响,为什么结果不同?

试试这样投射。 ~0 被提升为 int,它是有符号的,所以当你移位时它带有符号位

unsigned leftmost1 = ((unsigned)(~0)>>20);
printf("leftmost1 %u\n", leftmost1);

在第一种情况下,您正在进行 有符号右移 ,因为 ~0 会产生有符号值。带符号右移的确切行为是实现定义的,但大多数平台(包括您的平台)都会扩展符号位,因此对于您输入的 "all ones".

来说,移位是空操作

在第二种情况下,您正在进行无符号右移,因为 leftmost1 是一个 unsigned 值。所以你从左边移入零。

如果你想在没有中间赋值的情况下进行无符号移位,你可以这样做:

(~0u) >> 20

其中 u 后缀表示无符号文字。

0 的类型为 int~0 在典型的二进制补码机上是 -1。右移负数具有实现定义的结果,但常见的选择是移入 1 位,这对于 -1 保持数字不变(即 -1 >> anything-1)。

您可以通过编写 0uunsigned int 类型的文字)来解决此问题。这会强制操作在 unsigned int 中完成,如您的第二个示例:

unsigned leftmost1 = ~0;

这一行相当于 unsigned leftmost1 = -1,它隐式地将 -1(一个带符号的整数)转换为 UINT_MAX。下面的操作 (leftmost1 >> 20) 然后使用无符号算术。

~0 是一个 int。所以你的第一段代码不等同于第二段,它等同于

int tmp = ~0;
tmp = tmp >> 20;
unsigned leftmost1 = tmp;

当您右移一个负数时,您会看到符号扩展的结果。