-4

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);
}
Black_Zero
  • 445
  • 1
  • 6
  • 12
  • `Why the developer used division by 8 (/8) and modulus 8 (%8) expressions here and there`: Because there are typically 8 bits per byte (although the correct way to do it would be to use `CHAR_BIT` instead). – barak manos Jun 15 '15 at 07:12
  • 1
    Copy the expressions you have problems understanding, and break them down into their separate parts. Try to understand each part one by one, combine one small part with another small part and understand that combination, continue until you have the original complex expression and you should hopefully understand it all. – Some programmer dude Jun 15 '15 at 07:13
  • 3
    It's horribly written code, but if you re-format it and introduce some temporary variables for the intermediate terms then it should all start to make sense - it's a fairly common "pattern' for accessing a packed array of bits (8 elements per byte). – Paul R Jun 15 '15 at 07:16
  • @barak manos: that was certainly not an helpful comment at all. I am asking for the use of division and modulus operator not the "amount of bits" in bytes. – Black_Zero Jun 15 '15 at 07:48
  • 1
    @Black_Zero: well you asked: "why the developer used divison by **8** (/8) and modulus **8** (%8)" so it seems like a reasonable response. Perhaps your question needs to be clearer though - maybe you were asking about the use of `/` and `%` rather than the value `8` ? – Paul R Jun 15 '15 at 08:00
  • 1
    @PaulR: Thank you for backing me up on this one :) – barak manos Jun 15 '15 at 09:30

1 Answers1

2

please explain why the developer used divison by 8 (/8) and modulus 8 (%8) expressions here and there

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 bytes uint8_t data[n]. To access bit x in that byte array, you can for example do like this:

Given x = 17, bit x is then found in byte number 17/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:

uint8_t data[n];
...
size_t  byte_index = x / 8;
size_t  bit_index  = x % 8;
bool    is_bit_set;

is_bit_set = ( data[byte_index] & (1<<bit_index) ) != 0;
Lundin
  • 195,001
  • 40
  • 254
  • 396