C - 将 ~0 转换为 unsigned long

问题描述 投票:0回答:2

我见过使用

~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。

c casting type-conversion
2个回答
14
投票

在您的系统上

~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
的表示形式。


3
投票

除了 @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

© www.soinside.com 2019 - 2024. All rights reserved.