CS 105

Bits

Bit Masks and Bit Extraction

In this question, we will write helper functions for working with groups of bits inside a 32-bit unsigned integer.

A mask is an integer whose bits are used to select part of another integer. For example, the mask for the lower 5 bits is:

00000000 00000000 00000000 00011111

which is 0x0000001f.

For this question, assume that num_bits and offset are chosen so that the requested bits fit within a 32-bit value. In other words, you do not need to handle cases like asking for 40 bits or asking for 8 bits starting at offset 30.

Fill in the body of make_mask.

The function should return a uint32_t value whose lower num_bits bits are 1 and whose remaining bits are 0.

For example:

make_mask(0)  == 0x00000000
make_mask(1)  == 0x00000001
make_mask(4)  == 0x0000000f
make_mask(8)  == 0x000000ff
make_mask(32) == 0xffffffff

For this part, do not use general subtraction or multiplication. You may use increment (++), decrement (--), comparisons bitwise operators. Your code should be written as a loop that builds the mask one bit at a time.

#include <stdint.h>

uint32_t make_mask(unsigned num_bits) {
    uint32_t mask = 0;
    return mask;
}

Now fill in the body of extract_bits.

This function should extract num_bits bits from value, starting at bit position offset, and return those bits as a number shifted down to the low-order bits.

Bit positions are counted from the right, starting at 0.

For example, suppose:

uint32_t value = 0b11010110;

Then:

extract_bits(value, 1, 3)

should extract these three bits:

11010110
    ^^^

That gives 0b011, which is 3.

Your solution must call make_mask. Your solution may use >>, but it should not use << directly.

uint32_t extract_bits(uint32_t value, unsigned offset, unsigned num_bits) {
}

Using your functions above, what is the value of the following expression?

extract_bits(0b101101001011, 3, 5)

Give your answer in binary or decimal, and briefly explain how you got it.

Suppose we had written make_mask with this return type instead:

int32_t make_mask(unsigned num_bits);

What problems might this cause? Why is uint32_t a better return type for this function?

A common attempt at writing make_mask is:

uint32_t make_mask(unsigned num_bits) {
    return (1U << num_bits) - 1;
}

This looks compact, and for many values it works. What is the problem with this implementation?

(When logged in, completion status appears here.)