我见过使用
~0
生成所有 1
的位模式的低级按位表达式,然后将其用作掩码等。例如在 K&R 第 45 页上:
/* getbits: get n bits from position p */
unsigned getbits(unsigned x, int p, int n)
{
return (x >> (p+1-n)) & ~(~0 << n);
}
在我的机器中,
(unsigned long) ~0
的计算结果为 0x FF FF FF FF FF FF FF FF
。这让我们可以轻松生成大于 1
的 int
蒙版,而且还不错。
但是,
(unsigned long) ~0
不应该评估为0x 00 00 00 00 FF FF FF FF
吗?如果没有任何后缀,0
被视为整数常量,因此 ~0
的计算结果为 0x FF FF FF FF
。为什么将其转换为 unsigned long
不会产生零填充值?我在这里缺少什么?
编辑:在我的机器上,
sizeof(int)
和sizeof(long)
分别是4和8。
在您的系统上
~0
是一个带有位模式 int
的 FF FF FF FF
,表示十进制值 -1。
当您转换为
unsigned long
时,您将一种整数类型转换为另一种整数。其规则可以在 C(草案)标准 n1570 的 6.3.1.3 中找到:
1 当整数类型的值转换为_Bool以外的其他整数类型时,如果 该值可以用新类型表示,它没有改变。
2 否则,如果新类型是无符号的,则通过重复添加或来转换值 比新类型可以表示的最大值减一 直到该值在新类型的范围内。60)
60) 这些规则描述的是数学值的算术,而不是给定类型表达式的值。
第一条规则不适用,因为 -1 不能用
unsigned long
表示。应用第二条规则,即找到新值,如下所示
new-value = original-value + (ULONG_MAX + 1)
您的情况:
new-value = -1 + (ULONG_MAX + 1) = ULONG_MAX
因此新值是
ULONG_MAX
,它在您的系统上具有 FF FF FF FF FF FF FF FF
的表示形式。
除了 @SupportUkraine 的出色回应之外,您还应该意识到
return (x >> (p+1-n)) & ~(~0 << n);
会调用未定义的行为:
6.5.7 按位移位运算符
[...]
4 E1<< E2的结果是E1左移E2位位置;空出的位用零填充。如果 E1 具有无符号类型,则结果值为 E1 × 2E2,环绕。如果 E1 具有有符号类型和非负值,并且 E1 × 2E2 可以在结果类型中表示,那么这就是结果值;否则,行为是未定义的。
~0
具有类型 int
和值 -1
,因此 ~0 << n
对于 n > 0
具有未定义的行为。您应该使用 ~0U << n
来代替,并且使用 x
的类型大于 unsigned int
。对于所有无符号类型的 ~(0U * x) << n
,其通用表达式为 x
。