简体   繁体   中英

Implementation of logical right shift of negative numbers in c

有没有一种简单的方法可以在 c 中对负数进行逻辑右移,就像我们有 >> 算术右移一样?

Right-shifting negative numbers invoke implementation-defined behavior in C. What will happen is not specified by the standard, but left to the compiler to specify. So it can either result in an arithmetic shift, or a logical shift, or perhaps something else entirely (like rotation, though I've never heard of that). You can't know or assume which method that applies on your compiler, unless you read the specific compiler documentation.

Unsigned numbers always use logical shift however. So if you want logical shift on a negative number, portably, then convert to unsigned before the shift:

int32_t i = -1;

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

Similarly, if you want to guarantee an arithmetic shift:

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

if(negative)
{
  i = -i;
}

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

if(negative)
{
  i = -i;
}

Logical right shifting is done by casting the int value to unsigned before shifting:

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

Arithmetic right shifting cannot be dpne diretly with the >> operator on negative values in C as its effects are implementation defined. Here is a simple alternative without tests that replicates the sign bit for all values on 2s complement architectures:

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

And here is a simple test program:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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