简体   繁体   English

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

[英]Bit Operations - Indicating the Sign of a Signed Integer

Why does the following C code not work for returning -1 for negative numbers, 0 for 0s, and 1 for positive numbers? 为什么以下C代码不能用于返回-1表示负数,0表示0表示,1表示正数表示?

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

Specifically, when I pass in negative numbers, it returns 1. It seems like if I have a negative number, though (ie, the the least significant bit is a 1 after the 31 bit shift), XORing it with -1 will give me -2 (ie, all 1s and a 0 in the least significant bit location), and adding 1 would make it -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. >>通常会对签名数据进行算术移位,因此((-1) >> 31) == (-1) ,与您的假设相反。 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++? 请参阅C / C ++中是否有标准符号函数(signum,sgn)? for some ideas. 一些想法。

According to the C99 standard, the result of x >> n if x is negative is implementation defined. 根据C99标准,如果x为负,则x >> n的结果是实现定义的。 So the reason you are having a problem depends on your compiler and architecture. 所以你遇到问题的原因取决于你的编译器和架构。

However, it's most likely that the x is sign extended when you shift it ie the top bit is repeated to keep the sign the same as the operand. 但是,当你移动它时,x很可能是符号扩展,即重复顶部位以保持符号与操作数相同。 This is what happens with my compiler. 这是我的编译器发生的事情。 So for any negative number, x >> 31 is -1 . 因此,对于任何负数, x >> 31-1 Also, for any non zero number !x is 0 (ie false). 此外,对于任何非零数字!x为0(即假)。 This applies assuming x is a 32 bit integer. 这适用于假设x是32位整数。 If you make x an unsigned int, it should work, but consider the following alternative: 如果使x成为unsigned int,它应该可以工作,但请考虑以下替代方法:

(x < 0) ? -1 : ((x > 0) ? 1 : 0)

which I think is a bit less cryptic. 我认为这有点不那么神秘了。

And here is a program that you can use to see what your expression is doing 这是一个程序,您可以使用它来查看您的表达式正在做什么

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM