为什么下面的 C 代码不能返回负数的 -1、0 的 0 和正数的 1?
(((x >> 31) ^ -1) + 1) | (!x ^ 1);
具体来说,当我传入负数时,它返回 1。似乎如果我有一个负数(即,31 位移位后的最低有效位是 1),用 -1 异或会给我-2(即,所有 1 和最低有效位位置中的 0),加 1 将使其变为 -1。
为什么下面的 C 代码不能返回负数的 -1、0 的 0 和正数的 1?
(((x >> 31) ^ -1) + 1) | (!x ^ 1);
具体来说,当我传入负数时,它返回 1。似乎如果我有一个负数(即,31 位移位后的最低有效位是 1),用 -1 异或会给我-2(即,所有 1 和最低有效位位置中的 0),加 1 将使其变为 -1。
>>
will generally do arithmetic shift on signed data, so ((-1) >> 31) == (-1)
, contrary to your assumption. As pointed out by others, this is not guaranteed by the standard, but it is most likely true on modern systems. In any case, be careful with this type of bit twiddling. If portability is a concern or speed is not, you should do it a different way. See Is there a standard sign function (signum, sgn) in C/C++? for some ideas.
根据 C99 标准,x >> n
如果 x 为负的结果是实现定义的。因此,您遇到问题的原因取决于您的编译器和架构。
但是,当您移动它时,x 很可能是符号扩展的,即重复最高位以保持符号与操作数相同。这就是我的编译器发生的事情。所以对于任何负数,x >> 31
是-1
。此外,对于任何非零数!x
都是 0(即假)。这适用于假设 x 是 32 位整数。如果您将 x 设为无符号整数,它应该可以工作,但请考虑以下替代方案:
(x < 0) ? -1 : ((x > 0) ? 1 : 0)
我认为这不那么神秘。
这是一个程序,您可以使用它来查看您的表情在做什么
#include <stdio.h>
#define EVALUATE(x) printf("%s = %d\n", #x, x)
int main(int argc, char** argv)
{
unsigned int x = 51;
EVALUATE(x >> 31);
EVALUATE(((x >> 31) ^ -1));
EVALUATE(((x >> 31) ^ -1) + 1);
EVALUATE(!x);
EVALUATE(!x ^ 1);
EVALUATE((((x >> 31) ^ -1) + 1) | (!x ^ 1));
return 0;
}