Search code examples
c#bit-manipulation

Intent of the code with binary bitwise and shift operators, finding minimal version


I am trying to understand this code. It seem like trying to identify version but intent is not clear to me. Why us bit shifting is involved? And why 0x3F?

MinimumVersion = (version.Build & 0x7FFF) |
                 ((version.Minor & 0x3F) << 16) |
                 ((version.Major & 0x3F) << 22) |
                 0x70008000;

When I substitute variables with version parts, I get 1941995520. How does this construct works?

I did this

Console.WriteLine(0 & 0x7FFF);
Console.WriteLine((0 & 0x3F) << 16);
Console.WriteLine((15 & 0x3F) << 22);
Console.WriteLine(0x70008000);

Return is

0
0
62914560
1879080960

Sum of these is in fact 1941995520


Solution

  • To understand this you need to understand what I would call bit field manipulation. I'll start with the basics to make it clear

     x & y 
    

    This is a bitwise and. This means if a bit is set in the source and destination it will be set in the result. This code is using a mask

     x & 0x3F 
    

    remember the bit representation of 0x3F is 6 bits (0011 1111) so this is taking the bottom 6 binary (bit) digits and keeping those but removing everything else. You are left with a number that fits in 6 binary digits.


     a | b 
    

    This is a bitwise or. This means if a bit is set in either operand it will be set in the output.

    You can think of this as a concatenation if there is no "overlap" of bits.


    Here is an example, I will be using smaller numbers (and smaller bit fields) -- remember 1111 (4 bits) is equal to 15 or 0x0F

    So lets say we had

    x = 3 and y = 5 or (0x03 and 0x05)
    

    If we did

    (x & 0x0F)  << 4 | (y & 0x0F) 
    

    This would give us 0x35

    We are storing 2 4 bit values in 8 bits. We are also making sure x and y fit in 4 bits


    The code you are showing is doing something similar but with different sized bit fields.

    (version.Build & 0x7FFF) |
    ((version.Minor & 0x3F) << 16) |
    ((version.Major & 0x3F) << 22) |
     0x70008000;
    

    This says

    put the value in version.Build in the bottom 15 bitss

    put the value of version.Minor in the 22st - 17th bits

    put the value of version.Major in the 28th - 23nd bits

    set the bits located at 0b1110000000000001000000000000000 to true.

    So you end up with a number that gets bigger as version number gets bigger and fits in a long