我只是从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 >> 1
会0x000000007fffffff
提供0x00000000ffffffff >> 1
~0
的方式,0x00000000ffffffff
的值为~0 >> 1
。
为什么{{1}}不会改变位?
答案 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)
这至少部分是因为对负数的右移有两种不相容的解释:
算术移位,其结果与左操作数的符号相同,
一个逻辑班次,其中由班次腾出的位置总是用零填充。
实现可以选择(自由,不仅仅是在这些替代方案之间)。实际上,这意味着可移植代码不应该依赖于此类操作。