1

我有一个包含 8 位数据的位缓冲区,后跟 1 个奇偶校验位。这种模式会重复。缓冲区当前存储为八位字节数组。

示例(p 是奇偶校验位):

0001 0001 p000 0100 0p00 0001 00p01 1100 ...

应该成为

0001 0001 0000 1000 0000 0100 0111 00 ...

基本上,我需要剥离每第九位才能获得数据位。我怎样才能做到这一点?

这与某个时候在这里提出的另一个问题有关。

这是在 32 位机器上,因此相关问题的解决方案可能不适用。最大可能位数为 45,即 5 个数据八位字节

这是我到目前为止所尝试的。我创建了一个“布尔”数组,并根据八位字节的位集将位添加到数组中。然后,我查看数组的每第九个索引并通过它。然后将剩余的数组向下移动一个索引。然后我只剩下数据位了。我在想可能有更好的方法来做到这一点。

4

4 回答 4

2

您拥有一组位的想法很好。只需通过 32 位数字(缓冲区)实现位数组。

要从缓冲区中间删除一点:

void remove_bit(uint32_t* buffer, int* occupancy, int pos)
{
    assert(*occupancy > 0);
    uint32_t high_half = *buffer >> pos >> 1;
    uint32_t low_half = *buffer << (32 - pos) >> (32 - pos);
    *buffer = high_half | low_half;
    --*occupancy;
}

向缓冲区添加一个字节:

void add_byte(uint32_t* buffer, int* occupancy, uint8_t byte)
{
    assert(*occupancy <= 24);
    *buffer = (*buffer << 8) | byte;
    *occupancy += 8;
}

从缓冲区中删除一个字节:

uint8_t remove_byte(uint32_t* buffer, int* occupancy)
{
    uint8_t result = *buffer >> (*occupancy - 8);
    assert(*occupancy >= 8);
    *occupancy -= 8;
    return result;
}

您必须安排调用以使缓冲区永远不会溢出。例如:

buffer = 0;
occupancy = 0;
add_byte(buffer, occupancy, *input++);
add_byte(buffer, occupancy, *input++);
remove_bit(buffer, occupancy, 7);
*output++ = remove_byte(buffer, occupancy);
add_byte(buffer, occupancy, *input++);
remove_bit(buffer, occupancy, 6);
*output++ = remove_byte(buffer, occupancy);
... (there are only 6 input bytes, so this should be easy)
于 2012-06-11T10:51:47.197 回答
2

在伪代码中(因为您没有提供任何证明您已经尝试过的东西),为了简单起见,我可能会这样做:

  • 将数据(包括奇偶校验位)作为位流查看
  • 虽然还有一些位要读取:
    • 读取接下来的 8 位
    • 写入输出
    • 再读一点,然后丢弃

这“让你振作起来”,不再担心读取字节,这不再是一个有用的操作,因为你的字节与你想要丢弃的位交错。

于 2012-06-11T10:48:34.593 回答
1

我已经编写了辅助函数来读取未对齐的位缓冲区(这是用于 AVC 流,请参见此处的原始源)。代码本身是 GPL,我在这里粘贴有趣的(修改过的)位。

typedef struct bit_buffer_ {
  uint8_t * start;
  size_t size;
  uint8_t * current;
  uint8_t read_bits;
} bit_buffer;

/* reads one bit and returns its value as a 8-bit integer */
uint8_t get_bit(bit_buffer * bb) {
  uint8_t ret;
  ret = (*(bb->current) >> (7 - bb->read_bits)) & 0x1;
  if (bb->read_bits == 7) {
      bb->read_bits = 0;
      bb->current++;
  }
  else {
      bb->read_bits++;
  }
  return ret;
}

/* reads up to 32 bits and returns the value as a 32-bit integer */
uint32_t get_bits(bit_buffer * bb, size_t nbits) {
  uint32_t i, ret;
  ret = 0;
  for (i = 0; i < nbits; i++) {
    ret = (ret << 1) + get_bit(bb);
  }
  return ret;
}

您可以使用如下结构:

uint_8 * buffer;
size_t buffer_size;
/* assumes buffer points to your data */

bit_buffer bb;
bb.start = buffer;
bb.size = buffer_size;
bb.current = buffer;
bb.read_bits = 0;

uint32_t value = get_bits(&bb, 8);
uint8_t parity = get_bit(&bb);

uint32_t value2 = get_bits(&bb, 8);
uint8_t parity2 = get_bit(&bb);

/* etc */

我必须强调,这段代码非常完美,必须实施适当的边界检查,但它在我的用例中运行良好。

我将其作为练习留给您使用它来实现适当的位缓冲区读取器以获得灵感。

于 2012-06-11T10:36:06.133 回答
1

这也有效

void RemoveParity(unsigned char buffer[], int size)
{
    int offset = 0;
    int j = 0;

    for(int i = 1; i + j < size; i++)
    {
        if (offset == 0)
        {
            printf("%u\n", buffer[i + j - 1]);
        }
        else
        {
            unsigned char left = buffer[i + j - 1] << offset;
            unsigned char right = buffer[i + j] >> (8 - offset);
            printf("%u\n", (unsigned char)(left | right));
        }
        offset++;
        if (offset == 8)
        {
            offset = 0;
            j++; // advance buffer (8 parity bit consumed)
        }
    }
}
于 2012-06-11T13:19:35.223 回答