为什么〜0>> 1不换位?

时间:2016-12-06 20:07:28

标签: c bitwise-operators bit-shift

我只是从K& R c book第2章中学习,假设我有这段代码:

#include <stdio.h>
int
main(void)
{
    printf("0x%016llx\n", ~0); //0x00000000ffffffff

    printf("0x%016llx\n", ~0 >> 1); //0x00000000ffffffff
    printf("0x%016llx\n", 0x00000000ffffffff >> 1); //0x000000007fffffff
    return 0;
}

我希望~0 >> 10x000000007fffffff提供0x00000000ffffffff >> 1 ~0的方式,0x00000000ffffffff的值为~0 >> 1

为什么{{1}}不会改变位?

2 个答案:

答案 0 :(得分:6)

let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in // Place your action code here. } 格式说明符需要llx个参数,但您传入的是unsigned long long

由于int导致~0带有负值,因此转变并未给出您的期望。因此,执行右移保留符号位,即int位向左移位。

1后缀放在整数常量上以强制它们为正确的类型:

ULL

然后你会得到预期的输出:

printf("0x%016llx\n", ~0ULL);
printf("0x%016llx\n", ~0ULL >> 1);
printf("0x%016llx\n", 0x00000000ffffffffULL >> 1);

因为这些值现在是无符号的,所以0xffffffffffffffff 0x7fffffffffffffff 0x000000007fffffff 位总是会移到左边。

答案 1 :(得分:2)

此代码......

printf("0x%016llx\n", ~0)

...而您的其他类似示例显示未定义的行为,因为int的类型(~0)与对应的字段描述符%llx不对应,后者需要unsigned long long int 1}}。

评估表达式~0 >> 1表现出实现定义的(不是 un 定义的)行为,因为标准明确说明了

  

E1 >> E2的结果是E1右移E2位位置[,但是]如果   E1具有签名类型和负值,结果值是实现定义的。

(C2011,6.5.7 / 5)

这至少部分是因为对负数的右移有两种不相容的解释:

  • 算术移位,其结果与左操作数的符号相同,

  • 一个逻辑班次,其中由班次腾出的位置总是用零填充。

实现可以选择(自由,不仅仅是在这些替代方案之间)。实际上,这意味着可移植代码不应该依赖于此类操作。