Splitting out a frame of bytes

I think I see your point. We have meaningful names alright, but there are four of them for every chunk of bits we want to extract, and this doesn't scale well and leads to more confusion down the road. But my paper & pencil approach ends up being more concise than this. Let's do it my way:

1101 1110 1010 1101 1011 1110 1110 1111 // deadbeef
.... .... .... .... ..** ***. .... .... // we're after the stars
0000 0000 0000 0000 0011 1110 0000 0000 // so this is our mask

That mask's value is 15872 (or 0x3e00, which is easier to remember and harder to mistype). Of course the trailing zeros could be trailing ones or a mix of both, because we are going to discard them anyway when we shift bits, but this is tidier in my view. Our offset is 9 by definition (the dots to the right of the stars). Like Laurel and Hardy, the mask and the offset always go about together: what about putting them into a structure?

struct BitExtractor
{
  const uint32_t mask;
  const uint8_t  offset;
};

Now, we need a function that will do the extraction in one step:

uint32_t getBits (const uint32_t data, const struct BitExtractor b_e)
{
  return (data & b_e.mask) >> b_e.offset;
}

And we can christen our BitExtractor instances, each one with its own name:

const struct BitExtractor parameterAlfa    = {0x3e00, 9};
const struct BitExtractor parameterBravo   = {..., ...};
const struct BitExtractor parameterCharlie = ...;

Let's invoke it:

uint32_t result = getBits (0xdeadbeef, parameterAlfa);

And we find that result == 0x1f.

I've actually used a piece of paper and a pencil to work this out, but, of course, this can be done programmatically, once the procedure is clearly understood.

1 Like