C中逻辑右移,值为〜0

时间:2019-02-03 15:22:33

标签: c

我有一个非常简单的代码,其中逻辑移位以奇怪的方式处理〜0值

据我所知,它与有符号/无符号数据类型有关

A.x = dec(x)

我希望0111111,而不是1111111。 我也尝试过,没有成功

#include <stdio.h>

void printfbits(int x) {
    for (int i=7; i>=0;i--) {
        printf("%d", x>>i & 1);
    }
    printf("\n");
}

int main() {
    printfbits(~0>>1); 
}

4 个答案:

答案 0 :(得分:7)

在大多数平台上,int的长度为32位或64位。因此,您向右移动了8位以上,从而使您启用了8位以上:

11...11111111 >> 1

成为:

11...11111111 // if sign extension happens
01...11111111 // if not

如您所见,无论是否进行符号扩展,您都将看到所有1,因为您只打印了低8位。

答案 1 :(得分:4)

负号的右移是定义的实现。对于gcc,移入1,否则移入0。

使用强制转换时您处在正确的轨道上,但这无济于事,因为该函数仍然需要int。您需要将函数更改为采用unsigned char,并且必须屏蔽掉除最低字节以外的所有字节,然后才能执行函数调用中的移位。

#include <stdio.h>

void printfbits(unsigned char x) {
    for (int i=7; i>=0;i--) {
        printf("%d", x>>i & 1);
    }
    printf("\n");
}

int main() {
    printfbits((~0u & 0xff)>>1);
}

此外,请注意在常量0上使用U后缀。这使常量具有unsigned int类型。

答案 2 :(得分:1)

~0中的否定将与类型int一起发生。 但是,即使您执行~(unsigned char)0,由于隐式提升,使用int类型仍然会发生这种情况。 因此,您将在左侧获得更多的1位(int通常为32位大(必须至少为16位))。 您可以通过将否定结果强制转换为uint8_t来剥离它们。

我还建议对unsigned(而不是00 u)进行位操作,因为它们的语义更好地标准化了。

#include <stdio.h>
#include <stdint.h>

void printfbits(int x) {
    for (int i=7; i>=0;i--) {
        printf("%d", x>>i & 1);
    }
    printf("\n");
}

int main() {
    printfbits( (uint8_t)~0u >>1 );  //prints 01111111
}

答案 3 :(得分:0)

这是实现定义的有符号移位。但是在大多数2台补码机上:

enter image description here