C ++:掩码和解码位

uks*_*ksz 2 c++ mask masking

我刚刚遇到了一个我不了解的功能,我想知道您能否向我解释一下。

unsigned long long x(unsigned long long value, int begin, int end)
{
    unsigned long long mask = (1 << (end - begin)) - 1;
    return (value >> begin) & mask;
}
Run Code Online (Sandbox Code Playgroud)

谢谢
uksz

Bat*_*eba 5

函数的行为是undefined。它应该是

unsigned long long mask = (1ULL << (end - begin)) - 1;

1是一个int文字并且应用比其中的位更多的左移int是未定义的行为。1ULL是一个 unsigned long long 字面量。

一旦修复,它将可靠地只返回范围开始到结束的 0 和 1 位,其他地方都返回 0。

  • 0ULL - 1 等于 std::numeric_limits(unsigned long long)::max()。该标准坚持对无符号类型进行这种环绕。 (3认同)

the*_*ker 5

上述功能用作从数字中提取位范围的掩码。它可以分为四个步骤。

第一步:

mask = 1UL << (end - begin)
Run Code Online (Sandbox Code Playgroud)

<<逻辑移位1到左边由end - begin比特。由于1is 的二进制,因此000001移位3将对应于001000

第二步:

mask = mask - 1
Run Code Online (Sandbox Code Playgroud)

从上一步开始,我们已经确定,此时的掩码将是一个零序列,然后是一个零,然后是end - begin零个数。减去1该数字将导致end - begin最低有效位为1,其他所有内容均为01从我们前面的示例中减去,将得出结果000111

第三步:

value >> begin
Run Code Online (Sandbox Code Playgroud)

这将在逻辑上将目标编号(我们需要从中提取位的数字)向右移一位begin。由于我们希望这些位在范围内begin to end,因此我们可以在删除之前删除这些位begin

第四步:

(value >> begin) & mask
Run Code Online (Sandbox Code Playgroud)

对掩码进行按字符与运算将导致begin - end提取移位数的第一位。这是因为0 & x = 01 & x = x

正如Bathsheba在另一个答案中所指出的那样,应注意写1UL以确保要移位的数字是unsigned int。否则,将an移动int更多位int是未定义的行为。1UL是unsigned long long int带值的1