C ++:掩码和解码位

时间:2015-11-18 13:57:06

标签: 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;
}

感谢
uksz

4 个答案:

答案 0 :(得分:5)

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

第一步:

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 :(得分:4)

该功能的行为是未定义。它应该是

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

1int字面值,并且应用了更多左移位而不是位int中的位是未定义的行为。 1ULL是一个unsigned long long literal。

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

答案 2 :(得分:1)

第一行向右移动了一些(结束 - 开始)位移。 第二行通过多个(右)位移位向右移动。 这样,最后你将有一个等于“begin”和“end”之间位的掩码。

答案 3 :(得分: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