views:

105

answers:

1

How to extract the value represented by a particular set of bits in a given number i.e. if bits 11,12 & 13 are 1,1,0 then the value should be 6.

What is the most efficient way of doing the same? Also, it should be generic. I should be able to give start and end bit positions and should be able to extract the value represented by the bits present between the start and end positions.

Ex: 00000000 00000000 01100000 00011111

For the above number, considering 0th bit is from the right end, if I give this number, 0 as starting position and 2 as end position, then I should get the value 7.

Also, how do we take care of endianness also for the above problem?

+5  A: 
six = (value >> 12) & 7;

If you want to be generic,

inline unsigned extract_continuous_bits(unsigned value, int start, int end) {
    unsigned mask = (~0u) >> (CHAR_BIT*sizeof(value) - end - 1);
    return (value & mask) >> start;
}

assert(extract_continuous_bits(0x601f, 12, 14) == 6));
assert(extract_continuous_bits(0x601f, 0, 2) == 7));
assert(extract_continuous_bits(0xf0f0f0f0, 0, 31) == 0xf0f0f0f0));
assert(extract_continuous_bits(0x12345678, 16, 31) == 0x1234));
assert(extract_continuous_bits(0x12345678, 0, 15) == 0x5678));

And for endianness, see http://stackoverflow.com/questions/2213441/when-to-worry-about-endianness.

KennyTM
Matthew Flaschen
@Matthew: That makes sense. Updated.
KennyTM
Be warned that this has an edge case - it' not guaranteed to work if `start` and `end` specify the full width of the type (here, `unsigned`).
caf
Good point, caf. That could be fixed with a special case. if(end == (sizeof(unsigned) * CHAR_BIT - 1) }
Matthew Flaschen
OK I've updated the code so that it can handle `start=0`, `end=31` without special casing.
KennyTM