6

我正在查看名为BitStream的 C# 库,它允许您向标准 C#Stream对象写入和读取任意数量的位。我注意到在我看来是一个奇怪的设计决定:

将位添加到空字节时,这些位将添加到字节的 MSB。例如:

var s = new BitStream();
s.Write(true);
Debug.Assert(s.ToByteArray()[0] == 0x80);  // and not 0x01

var s = new BitStream();
s.Write(0x7,0,4);
s.Write(0x3,0,4);
Debug.Assert(s.ToByteArray()[0] == 0x73); // and not 0x37

但是,当引用数字中的位作为输入时,输入数字的第一位是 LSB。例如

//s.Write(int input,int bit_offset, int count_bits)
//when referencing the LSB and the next bit we'll write
s.Write(data,0,2); //and not s.Write(data,data_bits_number,data_bits_number-2)

对我来说似乎不一致。因为在这种情况下,当像前面的例子一样“逐渐”复制一个字节时(前四位,然后是后四位),我们不会得到原始字节。我们需要“向后”复制它(首先是最后四位,然后是前四位)。

我错过了那个设计有什么原因吗?具有这种行为的比特流的任何其他实现?对此有何设计考虑?

似乎ffmpeg比特流的行为方式我认为是一致的。在用函数中的指针ORing之前查看它移动字节的量。srcput_bits

作为旁注:

添加的第一个字节是字节数组中的第一个字节。例如

var s = new BitStream();
s.Write(0x1,0,4);
s.Write(0x2,0,4);
s.Write(0x3,0,4);
Debug.Assert(s.ToByteArray()[0] == 0x12); // and not s.ToByteArray()[1] == 0x12
4

3 回答 3

3

以下是一些额外的注意事项:

在布尔值的情况下 - 只需要一位来表示真或假。当该位被添加到流的开头时,该位流为“1”。当您将该流扩展到字节长度时,它会强制将零位填充到流的末尾,即使这些位在开始的流中并不存在。流中的位置是重要的信息,就像位的值一样,“1000000”或 0x80 的位流保证了流的后续读者可能认为他们读取的第一位是添加的第一位。

其次,其他数据类型(如整数)需要更多位来表示,因此它们在流中占用的空间比布尔值更多。当它们未在字节边界上对齐时,在同一流中混合不同大小的数据类型可能会非常棘手。

最后,如果您使用的是 Intel x86,那么您的 CPU 架构是“小端”,这意味着 LSB 首先就像您所描述的那样。如果您需要将流中的值作为大端存储,您需要在代码中添加一个转换层 - 类似于您在上面显示的内容,您可以按照您想要的顺序一次将一个字节推入流中. 这很烦人,但如果您需要与大端 Unix 机器互操作或协议规范可能需要,则通常需要这样做。

希望有帮助!

于 2010-02-22T22:17:40.783 回答
1

我错过了那个设计有什么原因吗?具有这种行为的比特流的任何其他实现?对此有何设计考虑?

我怀疑这个决定背后有什么重要意义。从技术上讲,只要作者和读者就顺序达成一致,这并不重要。

于 2009-09-10T18:13:55.173 回答
1

我同意埃拉扎尔的观点。

正如他/她所指出的,这是读者和作者不同意位顺序的情况。事实上,它们是不相容的。

于 2010-03-25T11:51:41.687 回答