我刚刚遇到一个我不理解的功能,我想知道你是否可以向我解释一下。
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
答案 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 = 0
和1 & x = x
。
正如Bathsheba的另一个答案所指出的,应该注意写1UL以确保被移位的数字是unsigned int
。否则将int
中的int
更多位移位是未定义的行为。 1UL是unsigned long long int
,其值为1
。
答案 1 :(得分:4)
该功能的行为是未定义。它应该是
unsigned long long mask = (1ULL << (end - begin)) - 1;
1
是int
字面值,并且应用了更多左移位而不是位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