在ANSI C第2.9节中,按位运算符,我无法理解这个特定的代码。
我知道每个按位运算符是如何工作的,但组合需要一些帮助。
getbits(x, 4, 3)
unsigned getbits(unsigned x, int p, int n) {
return (x >> (p + 1 - n)) & ~(~0 << n);
}
~0
是一个由二进制(111...111111
)组成的int
~0<<n
在低位(111...111000
)中引入了n
零。~(~0<<n)
翻转位(000...000111
),x>>(p+1-n)
x
向低位(00XXX...XXXXXX
)移动。&
运算结合了前两个结果:高零保持为零,下X
位(面向零)保持原样(00000...000XXX
)。
因此,此函数从位p
中检索n
位模式x
,但将(p+1-n)
位置移向较低位(即,放置在较低位置)。
该函数应该提取位置p
处宽度n
的位域。
此函数存在问题:
-
p + 1 - n
看似假的,但如果p
位域中最高有效位的位号,则它是位域右侧的位数,从0
开始编号,表示最低有效位。 -
如果位字段中包含最高有效
x
位,则代码具有实现定义的行为0
因为 是有符号整数。 应改用0U
。 -
该代码无法提取具有全宽为
unsigned int
的位域,因为移动大于或等于类型宽度的位数具有未定义的行为。移位应分为 2 部分,n - 1
位和另外 1 位。n - 1
将在[0..31]
范围内,因此变量偏移是完全定义的。
这是一个更便携的版本:
// extract `n` bits at position `p`. n in [1..32], p in `[1..32]`
unsigned getbits(unsigned x, int p, int n) {
return (x >> (p + 1 - n)) & ~(~0U << (n - 1) << 1);
}
以下是步骤:
0U
是无符号的整数空常量。~0U
设置了所有值位。~0 << (n - 1)
设置了除n - 1
低阶位之外的所有值位,这些位被清除。~0 << (n - 1) << 1
设置了除n
低阶位之外的所有值位,这些位被清除。~(~0 << (n - 1) << 1)
设置了n
低阶位。p + 1 - n
是比位域顺序低的位数x >> (p + 1 - n)
将值向右移动,将位域保留在低阶位位置。(x >> (p + 1 - n)) & ~(~0 << (n - 1) << 1)
屏蔽高阶位,只留下位域值。
请注意,还有其他方法可以计算掩码:
~0U >> (sizeof(unsigned) * CHAR_BIT - n)
(1U << (n - 1) << 1) - 1