带有符号 int 的位移位会重置一位太多

Bit shift with a signed int resets one bit too much

请看下面的代码片段,它基本上只是简单地将 1 个字节向左移动 24 位。

uint64_t i = 0xFFFFFFFF00000000;
printf("before: %016llX \n", i);
i += 0xFF << 24;
printf("after : %016llX \n", i);

// gives:
// before: FFFFFFFF00000000
// after : FFFFFFFEFF000000

最重要的32位是FFFFFFFE(看最后的E)。这不是我所期望的。我不明白为什么将 1 个字节向左移动 24 位会触及第 32 位(第 31 位应该是最后修改的)它将最后一个 F1111)更改为 E (1110)).

为了让它正常工作,我使用了 0xFF unsigned (0xFFU).

uint64_t i = 0xFFFFFFFF00000000;
printf("before: %016llX \n", i);
i += 0xFFU << 24;
printf("after : %016llX \n", i);

// gives:
// before: FFFFFFFF00000000
// after : FFFFFFFFFF000000

为什么带符号的 int (0xFF) touch/reset 位移多了一位?

你左移到了符号位。

整数常量 0xFF 的类型为 int。假设 int 是 32 位,表达式 0xFF << 24 将设置为 1 的位移动到有符号整数触发器的高位位 undefined behavior ,在您的情况下表现为意外值。

这在 C standard 的第 6.5.7p4 节中有详细说明:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1×2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1×2E2is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

通过使用 U 后缀,这使得常量具有类型 unsigned int,并且将设置为 1 的位移入高位是有效的,因为没有符号位。