The function is supposed to extract a bitfield of width n
at position p
.
There are problems in this function:
p + 1 - n
seems bogus but it is the number of bits to the right of the bitfield if p
is the bit number of the most significant bit in the bitfield, numbered from 0
for the least significant bit..
the code has implementation defined behavior if the most significant bit of x
is included in the bitfield because 0
is a signed integer. 0U
should be used instead.
the code does not work to extract a bitfield that has the full width of unsigned int
, because shifting by a number of bits greater or equal to the width of the type has undefined behavior. The shift should be split in 2 parts, n - 1
bits and an additional 1 bit. n - 1
will be in the range [0..31]
so the variable shift is fully defined.
Here is a more portable version:
// extract `n` bits at position `p`. n in [1..32], p in `[1..32]`
unsigned getbits(unsigned x, int p, int n) {
return (x >> (p + 1 - n)) & ~(~0U << (n - 1) << 1);
}
Here are the steps:
0U
is the unsigned int null constant.
~0U
has all its value bits set.
~0 << (n - 1)
has all its value bits set except for the n - 1
low order bits, which are cleared.
~0 << (n - 1) << 1
has all its value bits set except for the n
low order bits, which are cleared.
~(~0 << (n - 1) << 1)
has the n
low order bits set.
p + 1 - n
is the number of bits with lower order than the bitfield
x >> (p + 1 - n)
shifts the value to the right, leaving the bitfield in the low order bit positions.
(x >> (p + 1 - n)) & ~(~0 << (n - 1) << 1)
masks the higher order bits, leaving just the bitfield value.
Note that there are other ways to compute the mask:
~0U >> (sizeof(unsigned) * CHAR_BIT - n)
(1U << (n - 1) << 1) - 1