问题
I just came across a function I dont understand, and I was wondering if you could explain it to me.
unsigned long long x(unsigned long long value, int begin, int end)
{
unsigned long long mask = (1 << (end - begin)) - 1;
return (value >> begin) & mask;
}
Thanks
uksz
回答1:
The above function serves as a mask to extract a range of bits from a number. It can be broken down into four steps.
First step:
mask = 1UL << (end - begin)
The <<
logically shifts 1
to the left by end - begin
bits. Since the binary of 1
is 000001
, a shift by 3 would correspond to 001000
.
Second step:
mask = mask - 1
We have established from the previous step that mask at that point would be a sequence of zeroes, followed a one, followed by end - begin
number of zeroes. Subtracting 1
from such a number will result in the end - begin
least significant bits being 1
, with everything else as 0
. Subtracting 1
from our previous example yields 000111
.
Third step:
value >> begin
This will logically shift the target number (the one from which we need to extract bits) to the right by begin
bits. Since we want the bits in the range begin to end
, we can leave remove the bits before begin
.
Fourth step:
(value >> begin) & mask
Taking the characterwise AND with the mask will result in the first begin - end
bits of the shifted number being extracted. This is because the 0 & x = 0
and 1 & x = x
.
As pointed out in the other answer by Bathsheba, care should be taken to write 1UL to ensure that the number being shifted is an unsigned int
. Else shifting an int
by more bits in that int
is undefined behavior. 1UL is an unsigned long long int
with the value 1
.
回答2:
The behaviour of the function is undefined. It should be
unsigned long long mask = (1ULL << (end - begin)) - 1;
1
is an int
literal and applying more left shifts than there are bits in that int
is undefined behaviour. 1ULL
is an unsigned long long literal.
Once this is fixed, it will reliably return just the 0 and 1 bits in the range begin to end, and 0 everywhere else.
回答3:
The first line is shifting to the left the number by a number of (end - begin) bit shifts. The second line is shifting to the right by a number of (right) bit shifts. This way at the end you will have a mask that is equal to the bits between "begin" and "end".
回答4:
(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
来源:https://stackoverflow.com/questions/33781952/c-mask-and-decoding-bits