在C#中设计BitStream

我正在查看名为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比特流的行为方式与我认为一致.在使用the put_bits function中的src指针进行OR操作之前,查看它移动字节的数量.

作为旁注:

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

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

解决方法:

以下是一些其他注意事项:

在布尔值的情况下 – 只需要一位表示true或false.当该位被添加到流的开头时,比特流为“1”.当您将该流扩展为字节长度时,它会强制将零位填充到流的末尾,即使这些位在流中不存在也不会存在.流中的位置就像位的值一样是重要的信息,并且比特流“1000000”或0x80保证了流的后续读取器可能具有的第一位是它们读取的第一位是添加的第一位.

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

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

希望有所帮助!

上一篇:LeetCode 191. Number of 1 Bits


下一篇:python的debug神器PySnooper