Home > Net >  Making bitmasks in C
Making bitmasks in C

Time:04-09

I'm new to bit manipulation but I'm struggling to translate it to code. For the following function I need to make a bitmask

void make_bitmask(unsigned int width, unsigned int shift,unsigned int* mask)

The bitmask function is supposed to have a width and a shift. if w=5 and s=1 it should give 00111110.

How should I approach this? This is my latest code I've been trying:

*mask |= width << shift;

Changed to *mask = ((1 << width) - 1) << shift;

Unit test:

static void test_make_bitmask_correct_width(void)
{
 unsigned int mask = 0;
make_bitmask(1,0,&mask)
TEST_ASSERT_EQUAL_HEX32(0x1, mask);
make_bitmask(2,0,&mask)
TEST_ASSERT_EQUAL_HEX32(0x3, mask);
make_bitmask(5,0,&mask)
TEST_ASSERT_EQUAL_HEX32(0x1f, mask);
make_bitmask(32,0,&mask)
TEST_ASSERT_EQUAL_HEX32(0xffffffff, mask); // the one that is currently failing  mask is 0x000000000

CodePudding user response:

void make_bitmask(unsigned int width, unsigned int shift,unsigned int *mask)
{
    /*  With unlimited arithmetic, (1 << width) - 1 would give us a mask of
        width bits, starting at the low bit position.  E.g., with width 3, 1 <<
        3 would give binary 1000, and subtracting one would give 111, a mask of
        3 bits.  However, in C arithmetic, if width is the full width of an
        unsigned int, then "1u << width" would overflow.  To avoid this, if
        width is positive, we shift 2u by width-1.  If width is zero, we simply
        use the hardcoded result for a mask of zero bits, zero.
    */
    unsigned int t = width ? (2u << width-1) - 1u : 0u;

    //  Shift the mask to the desired position and store it.
    *mask = t << shift;
}

CodePudding user response:

The decimal value 5 is binary 00000101. Shifting it left by one bit gives you 00001010.

If you want 5 to turn into 00011111 (decimal 31) then the easiest solution is to find out the value 00100000 (decimal 32) and the subtracting one.

Remembering that we're dealing with powers of 2, if you raise 2 to the power of 5 we get 32, and can then subtract one to get the base mask. But instead of using the pow function or multiplying in a loop, we can just shift the value 1 five steps left (1 << 5).

Putting it all together, the you should shift 1 left by width bits, subtract 1, and then shift the result shift bits to the left:

*mask = ((1 << width) - 1) << shift;

With width == 5 and shift == 1 then the above will give you binary 00111110 (decimal 62).

  • Related