-2

I would to implement a function like this:

int read_single_bit(unsigned char* buffer, unsigned int index)

where index is the offset of the bit that I would want to read.

How do I use bit shifting or masking to achieve this?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
PenguinEngineer
  • 295
  • 1
  • 8
  • 30

3 Answers3

4

You might want to split this into three separate tasks:

  1. Determining which char contains the bit that you're looking for.
  2. Determining the bit offset into that char that you need to read.
  3. Actually selecting that bit out of that char.

I'll leave parts (1) and (2) as exercises, since they're not too bad. For part (3), one trick you might find useful would be to do a bitwise AND between the byte in question and a byte with a single 1 bit at the index that you want. For example, suppose you want to get the fourth bit out of a byte. You could then do something like this:

Byte:   11011100
Mask:   00001000
----------------
AND:    00001000

So think about the following: how would you generate the mask that you need given that you know the bit index? And how would you convert the AND result back to a single bit?

Good luck!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
1
buffer[index/8] & (1u<<(index%8))

should do it (that is, view buffer as a bit array and test the bit at index).

Similarly:

buffer[index/8] |= (1u<<(index%8))

should set the index-th bit.

Or you could store a table of the eight shift states of 1 and & against that

unsigned char bits[] = { 1u<<0, 1u<<1, 1u<<2, 1u<<3, 1u<<4, 1u<<5, 1u<<6, 1u<<7 }; 

If your compiler doesn't optimize those / and % to bit ops (more efficient), then:

 unsigned_int / 8  == unsigned_int >> 3
 unsigned_int % 8  == unsigned_int & 0x07  //0x07 == 0000 0111

so

 buffer[index>>3] & (1u<<(index&0x07u))  //test
 buffer[index>>3] |= (1u<<(index&0x07u)) //set
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • Shifting left is mod 8? – chux - Reinstate Monica Feb 12 '16 at 22:21
  • Hmm, on second thought, I don't think so. But are you aware why actually not? With minor other constraints you would have UB. You should write your code more safely. (Sorry, had to dummy-edit to remove the DV. – too honest for this site Feb 12 '16 at 23:14
  • OP declared index as an `unsigned int` and `buffer` as an unsigned char array. There should be no issue with bit ops on unsigned integers. – Petr Skocik Feb 12 '16 at 23:16
  • Oh, you very well do signed arithmetics. It is a really well-meant hint to research where any why (that is very important knowledge, no nastyness). – too honest for this site Feb 12 '16 at 23:17
  • @Olaf I think I know what you're hinting at. The `1` literal is a `signed int` and I would it UB if the bit from the left-shift hit the sign bit, but it doesn't because luckily I'm only shifting the lower 8 bits, but I still had better written `1u`, correct? – Petr Skocik Feb 12 '16 at 23:31
  • @PSkocik: Exactly. Sorry, but that is really important and many people ignore that. FYI: Using an `int` constant on the LHS of a bitshift triggered my first comment (and the DV), but some minutes later somehow it came into my mind you did not shift that far. – too honest for this site Feb 13 '16 at 08:49
  • @Olaf Thank you for pointing that out. It's actually useful info for some software of mine. – Petr Skocik Feb 13 '16 at 12:29
0

One possible implementation of your function might look like this:

int read_single_bit(unsigned char* buffer, unsigned int index)
{
    unsigned char c = buffer[index / 8]; //getting the byte which contains the bit
    unsigned int bit_position = index % 8; //getting the position of that bit within the byte

    return ((c >> (7 - bit_position)) & 1);
    //shifting that byte to the right with (7 - bit_position) will move the bit whose value you want to know at "the end" of the byte.
    //then, by doing bitwise AND with the new byte and 1 (whose binary representation is 00000001) will yield 1 or 0, depending on the value of the bit you need.
}
Polb
  • 640
  • 2
  • 8
  • 21