C中逻辑右移,值为~0

C中逻辑右移,值为~0,c,C,我有一个非常简单的代码,其中逻辑移位以奇怪的方式处理~0值 据我所知,它与有符号/无符号数据类型有关 #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); }

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

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

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

在大多数平台上,
int
的长度为32位或64位。因此,您将超过8位向右移位,这将使您启用超过8位:

11...11111111 >> 1
变成:

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

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

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


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

您使用cast的方法是正确的,但是没有帮助,因为函数仍然需要
int
。您需要将函数更改为获取
无符号字符
,并且在执行函数调用中的移位之前,必须屏蔽除最低字节以外的所有字节

#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);
}
#包括
void printfbits(无符号字符x){
对于(int i=7;i>=0;i--){
printf(“%d”,x>>i&1);
}
printf(“\n”);
}
int main(){
printfbit((~0u&0xff)>>1);
}

另外,请注意在常量0上使用了
U
后缀。这使常数的类型为
无符号int

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

我还建议对
unsigned
s(
0
u,而不是
0
)执行位运算,因为语义对于这些操作更标准化

#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
}
#包括
#包括
无效打印FBITS(int x){
对于(int i=7;i>=0;i--){
printf(“%d”,x>>i&1);
}
printf(“\n”);
}
int main(){
printfbits((uint8_t)~0u>>1);//打印01111111
}

int类型是32位,不是8位。对!我试过char,现在它可以用了@AlexF C
int
s不一定是32位!它们可以是16位或更大的任意大小。现在常见的大小是16、32和64位。不管符号扩展如何,OP仍然会看到所有
1
s,假设
int
大于8位。虽然C标准确实说
>
的行为是在第一个操作数为负时实现定义的,我向您提出挑战,希望您能找到一个现代C实现,它在默认情况下并没有将其定义为。标准中的语言基本上是古代CPU编译器的遗物,这些编译器使用的不是表示有符号整数。@IlmariKaronen:如果有人有一定的影响力,真诚地努力识别到20世纪90年代末几乎标准化的所有有用的东西,这将是很有帮助的,在编译器编写人员确定未定义的行为意味着“跳过轨道,即使执行环境将定义有用的行为”。我测试了一个编译器,其中有符号右移与无符号右移的处理方式相同;在我的投诉(可能还有其他测试人员的投诉)之后,供应商认识到,尽管这种行为是允许的,处理器可以更快地处理……在某些情况下,符号扩展转换比符号扩展转换更快,但符号扩展行为在two’s-Complete平台上显然更可取。有趣的是,C99标准决定将负数的左移从大多数实现中严格定义改为所有实现中未定义的行为,尽管C99要求64位或更长的无符号类型,这使得C99在除了两个互补平台之外的任何平台上都无法实现,因为在这些平台上通常只有一个合理的行为。
#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
}