C++:掩码和解码位

C++: Mask and decoding bits

我刚刚遇到一个我不明白的功能,我想知道你是否可以给我解释一下。

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

谢谢
uksz

第一行将数字向左移动若干(结束 - 开始)位移位。 第二行向右移动了一些(右)位移位。 这样最后你将得到一个等于 "begin" 和 "end".

之间的位的掩码

函数的行为是未定义。应该是

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

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

一旦这个问题得到解决,它将可靠地return范围内的 0 和 1 位开始结束,其他地方都是 0。

上述函数用作从数字中提取一系列位的掩码。它可以分为四个步骤。

第一步:

mask = 1UL << (end - begin)

<< 逻辑上将 1 向左移动 end - begin 位。由于 1 的二进制是 000001,移位 3 将对应于 001000.

第二步:

mask = mask - 1

我们从上一步中确定,该点的掩码将是一系列零,然后是一个,然后是 end - begin 个零。从这样的数字中减去 1 将导致 end - begin 最低有效位为 1,其他所有位为 0。从我们前面的例子中减去 1 得到 000111.

第三步:

value >> begin

这将在逻辑上将目标数字(我们需要从中提取位的数字)向右移动 begin 位。因为我们想要 begin to end 范围内的位,所以我们可以删除 begin.

之前的位

第四步:

(value >> begin) & mask

将字符与掩码进行 AND 将导致提取移位数字的前 begin - end 位。这是因为 0 & x = 01 & x = x.

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

(1) 1 in the expression implies 32 bit number on 32 bit machines.  
So we need uul after 1 to make it 64 bit. Will work for MOST of the              
cases.          
unsigned long long mask = (1ull << (end - begin)) - 1;  

(2) When begin=0, end=63, we will still see the wrong mask in case#1  
The mask will come out be 0x7FFFFFFFFFFFFFFF  
The following will fix that problem as well.  
unsigned long long mask = ((1ull << end) - (1ull << begin)) | (1ull << end);

This will generate the mask 0xFFFFFFFFFFFFFFFF