这个按位运算符的位置是否改变了行为?
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
中的值。
这两行代码等价吗?
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
中的值。