这个按位运算符的位置是否改变了行为?

Does the position of this bit-wise operator change the behavior?

这两行代码等价吗?

P1->OUT &= ~(uint8_t)(1<<1);

P1->OUT &= (uint8_t)(~(1<<1));

这取决于P1->OUT的类型和系统。 1 << 1 的结果是 int.

类型

我正在考虑 int n; 而不是 1 << 1

的一般情况

P1->OUT &= ~(uint8_t)(n);

操作数将在 ~(整数提升)之前再次扩大到 int,并且 ~ 将应用于 int。结果将设置所有高阶位 8...k。如果 P1->OUT 是 8 位宽,那没问题,但如果它有更多位,那么结果就不是你所期望的。

这个更糟:

P1->OUT &= (uint8_t)(~(n));

~ 操作数将再次应用于 int 并且 that 将被转换为 uint8_t。现在,如果 ~n 实际上是负数(已设置其符号位) - 如果 ~(1 << 1) 它将是负数 - 它在二进制补码实现中会很好,但 完全 在 1 的补码和符号与大小实现中不正确,因为位表示不相同。


进行位运算的正确方法始终是使用 unsigned int 或更宽的二进制补码:

P1->OUT &= ~(1U << n);

P1->OUT &= (~(1U << n)) & 0xFF;

避免算术转换和整数提升产生有符号数。

TL;DR — 不!(它们并不总是相同的,结果取决于 P1->OUT 的类型。)

我假设的是 2 的补码运算的正常情况。如果你苦于符号量级或1的补码算术,你得好好想想,但结论可能是一样的(不总是一样的)。

案例一:

  • (1<<1) 是一个 int 值 (0x02)。
  • (uint8_t)(1<<1) 转换为 uint8_t,但值仍然是 0x02.
  • ~(uint8_t)(1<<1) 再次将 uint8_t 值转换为 int (usual arithmetic conversions) 并将按位反转运算符 ~ 应用于结果。

假设一个 32 位 int 类型,你得到 0xFFFFFFFD&P1->OUT:

P1->OUT &= 0xFFFFFFFD;

案例二:

  • (1<<1) 是一个 int 值 (0x02)。
  • ~(1<<1) 是一个 int 值 — 假设 32 位 int,该值是 0xFFFFFFFD.
  • (uint8_t)~(1<<1) 转换为 uint8_t,将较高有效字节中的位归零。

假设一个 32 位 int 类型,你得到 0x000000FD&P1->OUT:

P1->OUT &= 0x000000FD;

因此,与 P1->OUT 组合的值是不同的,但效果还取决于 P1->OUT 的(未指定)类型。如果是uint8_t,则没有区别;如果是 uint64_t,则可能存在巨大差异,但它还取决于执行复合赋值之前 P1->OUT 中的值。