为什么 ~0 >> 1 不移动位?
Why ~0 >> 1 doesn't shift the bit?
我刚从 K&R c 书第 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
会像 0x00000000ffffffff >> 1
那样给出 0x000000007fffffff
,~0
的值是 0x00000000ffffffff
。
为什么 ~0 >> 1
不移动位?
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
因为值现在是无符号的,所以 0
位总是移到左边。
此代码...
printf("0x%016llx\n", ~0)
...和您的其他类似示例表现出未定义的行为,因为 ~0
的类型 (int
) 与相应的字段描述符 %llx
不对应,这需要unsigned long long int
.
评估表达式 ~0 >> 1
表现出实现定义的(不是 un 定义的)行为,因为标准明确表示
The result of E1 >> E2
is E1
right-shifted E2
bit positions [, but] If
E1
has a signed type and a negative value, the resulting value is implementation-defined.
(C2011, 6.5.7/5)
出现这种情况至少部分是因为对负数右移有两种不相容的解释:
一个算术移位,其中结果与左操作数的符号相同,并且
一个逻辑移位,移位空出的位置总是用零填充。
实现可以选择(自由地,而不仅仅是在这些备选方案之间)。实际上,这意味着可移植代码不应依赖此类操作。
我刚从 K&R c 书第 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
会像 0x00000000ffffffff >> 1
那样给出 0x000000007fffffff
,~0
的值是 0x00000000ffffffff
。
为什么 ~0 >> 1
不移动位?
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
因为值现在是无符号的,所以 0
位总是移到左边。
此代码...
printf("0x%016llx\n", ~0)
...和您的其他类似示例表现出未定义的行为,因为 ~0
的类型 (int
) 与相应的字段描述符 %llx
不对应,这需要unsigned long long int
.
评估表达式 ~0 >> 1
表现出实现定义的(不是 un 定义的)行为,因为标准明确表示
The result of
E1 >> E2
isE1
right-shiftedE2
bit positions [, but] IfE1
has a signed type and a negative value, the resulting value is implementation-defined.
(C2011, 6.5.7/5)
出现这种情况至少部分是因为对负数右移有两种不相容的解释:
一个算术移位,其中结果与左操作数的符号相同,并且
一个逻辑移位,移位空出的位置总是用零填充。
实现可以选择(自由地,而不仅仅是在这些备选方案之间)。实际上,这意味着可移植代码不应依赖此类操作。