位操作 - 指示有符号整数的符号

时间:2013-04-22 14:09:39

标签: c binary bit-manipulation

为什么以下C代码不能用于为负数返回-1,为0返回0,为正数返回1?

(((x >> 31) ^ -1) + 1) | (!x ^ 1);

具体来说,当我传入负数时,它返回1.虽然看起来我有一个负数(即31位移位后最低有效位为1),但是它与-1进行异或运算会给我-2(即所有1和最低有效位的0),加1会使它为-1。

2 个答案:

答案 0 :(得分:1)

>>通常会对签名数据进行算术移位,因此((-1) >> 31) == (-1)与您的假设相反。正如其他人所指出的那样,标准并不能保证这一点,但在现代系统中很可能是这样。在任何情况下,要小心这种类型的钻头。如果可移植性是一个问题或速度不是,你应该以不同的方式。有关一些想法,请参阅Is there a standard sign function (signum, sgn) in C/C++?

答案 1 :(得分:1)

根据C99标准,如果x为负,则x >> n的结果是实现定义的。所以你遇到问题的原因取决于你的编译器和架构。

但是,当你移动它时,x很可能是符号扩展,即重复最高位以保持符号与操作数相同。这是我的编译器发生的事情。因此,对于任何负数,x >> 31-1。此外,对于任何非零数字!x都是0(即假)。这适用于假设x是32位整数。如果使x成为unsigned int,它应该可以工作,但请考虑以下替代方法:

(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;
}