C++: Mask and decoding bits

笑着哭i 提交于 2020-01-04 05:35:11

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!