c中负数逻辑右移的实现

时间:2016-10-04 13:01:12

标签: c operators bit-shift

是否有一种简单的方法可以在c中对负数进行逻辑右移,例如我们的>>算术右移?

2 个答案:

答案 0 :(得分:4)

右移负数在C中调用实现定义的行为。将发生的事情不是由标准指定的,而是由编译器指定。因此它可以导致算术移位,或逻辑移位,或者可能导致完全不同的东西(如旋转,尽管我从未听说过)。除非您阅读特定的编译器文档,否则您无法知道或假设哪种方法适用于您的编译器。

无符号数总是使用逻辑移位。因此,如果您希望在负数上进行逻辑移位,则可以移位,然后在移位前转换为无符号:

int32_t i = -1;

i = (int32_t) ((uint32_t)i >> n); // guaranteed to give logical shift

同样,如果你想保证算术移位:

int32_t i = -1;
bool negative = i < 0;

if(negative)
{
  i = -i;
}

i = (int32_t) ((uint32_t)i >> n);

if(negative)
{
  i = -i;
}

答案 1 :(得分:0)

通过在移位前将int值转换为unsigned来完成逻辑右移:

int lsr(int n, int shift) {
    return (int)((unsigned)n >> shift);
}

算术右移不能直接使用>>运算符对C中的负值进行,因为它的效果是实现定义的。这是一个简单的替代方案,没有测试复制2s补码架构上所有值的符号位:

int asr(int n, int shift) {
    unsigned u = (unsigned)n;
    return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}

这是一个简单的测试程序:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int lsr(int n, int shift) {
    return (int)((unsigned)n >> shift);
}

int asr(int n, int shift) {
    unsigned u = (unsigned)n;
    return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}

int main(int argc, char *argv[]) {
    int n = (argc < 2) ? -2 : strtol(argv[1], NULL, 0);
    int shift = (argc < 3) ? 2 : strtol(argv[2], NULL, 0);

    printf("%d >> %d = %d\n", n, shift, asr(n, shift));
    printf("%d >>> %d = %d\n", n, shift, lsr(n, shift));

    return 0;
}