0

Given a data stream in C, I need to read the nth element which is x bits wide. x can vary from 1-64. How do I do this in C? I tried some bit fiddling but could not come up with a solution.

For example, for a data stream

01101010 11010101 11111111 00000010 00000000 10000000
                      ==== ======

if the data is 10-bit wide and the element to parse is the third element. The expected data should be 1111 000000.

The data stream is byte-addressable.

Jongware
  • 22,200
  • 8
  • 54
  • 100
  • 1
    If you just need results and don't care about efficiency, you can always grab each bit one at a time and reassemble them into your number. – Drew McGowen Aug 13 '14 at 18:08
  • 5
    This seems like a pretty simple case of bit shifting and masking. Can you share what didn't work for you and why? I'd like to see exactly what you mean by "bit fiddling." – skrrgwasme Aug 13 '14 at 18:10
  • 1
    Where's @FiddlingBits when you need him ;) – Drew McGowen Aug 13 '14 at 18:41
  • Search for sample code of LZW encoding. Reading bits is not hard, just a bit *shifty* (hint). – Jongware Aug 13 '14 at 21:37

2 Answers2

1

First find out what the most significant bit represents. Specifically, does it represent bit 0 or bit 7 in your bit stream.

To find the nth element, you will need to find which byte it starts on ((n*x)/8), get the appropriate bits from that byte, then get the remaining bits from the following byte or bytes.

But, which bits should be taken from the bytes depends on what the most significant bit represents.

jxh
  • 69,070
  • 8
  • 110
  • 193
1
#include <stdio.h>
#include <stdint.h>

uint64_t bit_slice(const uint8_t ds[], int start, int end){
    //index start, end {x | 1 <= x <= 64 }
    uint64_t s = 0;//memcpy(&s, ds, 8);
    int i, n = (end - 1) / 8;
    for(i = 0; i <= n; ++i)
        s = (s << 8) + ds[i];
    s >>= (n+1) * 8 - end;
    uint64_t mask = (((uint64_t)1) << (end - start + 1))-1;//len = end - start + 1
    s &= mask;
    return s;
}

int main(void){
    uint8_t data[8] = {
        0b01101010, 0b11010101, 0b11111111, 0b00000010, 0b00000000, 0b10000000 //0b... GCC extention
    };
    unsigned x = bit_slice(data, 21, 30);
    printf("%X\n", x);//3C0 : 11 1100 0000
    return 0;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70