I have encountered the following C function while working on a legacy code and I am compeletely baffled, the way the code is organized. I can see that the function is trying to set bits at given position in bit stream but I can't get my head around with individual statements and expressions. Can somebody please explain why the developer used divison by 8 (/8) and modulus 8 (%8) expressions here and there. Is there an easy way to read these kinds of bit manipulation functions in c?
static void setBits(U8 *input, U16 *bPos, U8 len, U8 val)
{
U16 pos;
if (bPos==0)
{
pos=0;
}
else
{
pos = *bPos;
*bPos += len;
}
input[pos/8] = (input[pos/8]&(0xFF-((0xFF>>(pos%8))&(0xFF<<(pos%8+len>=8?0:8-(pos+len)%8)))))
|((((0xFF>>(8-len)) & val)<<(8-len))>>(pos%8));
if ((pos/8 == (pos+len)/8)|(!((pos+len)%8)))
return;
input[(pos+len)/8] = (input[(pos+len)/8]
&(0xFF-(0xFF<<(8-(pos+len)%8))))
|((0xFF>>(8-len)) & val)<<(8-(pos+len)%8);
}
First of all, note that the individual bits of a byte are numbered 0 to 7, where bit 0 is the least significant one. There are 8 bits in a byte, hence the "magic number" 8.
Generally speaking: if you have any raw data, it consists of
n
bytes and can therefore always be treated as an array of bytesuint8_t data[n]
. To access bitx
in that byte array, you can for example do like this:Given
x = 17
, bit x is then found in byte number17/8 = 2
. Note that integer division "floors" the value, instead of 2.125 you get 2.The remainder of the integer division gives you the bit position in that byte,
17%8 = 1
.So bit number 17 is located in byte 2, bit 1.
data[2]
gives the byte.To mask out a bit from a byte in C, the bitwise AND operator
&
is used. And in order to use that, a bit mask is needed. Such bit masks are best obtained by shifting the value 1 by the desired amount of bits. Bit masks are perhaps most clearly expressed in hex and the possible bit masks for a byte will be(1<<0) == 0x01
,(1<<1) == 0x02
,(1<<3) == 0x04
,(1<<4) == 0x08
and so on.In this case
(1<<1) == 0x02
.C code: