我正在查看名为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中的OR
指针查看src
前的字节移位量。
作为旁注:
添加的第一个字节是字节数组中的第一个字节。例如
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
答案 0 :(得分:3)
以下是一些其他注意事项:
在布尔值的情况下 - 只需要一位表示true或false。当该位被添加到流的开头时,比特流为“1”。当您将该流扩展为字节长度时,它会强制将零位填充到流的末尾,即使这些位在流中不存在也不会存在。流中的位置就像位的值一样是重要的信息,并且比特流“1000000”或0x80保证了流的后续读取器可能具有的第一位是它们读取的第一位是添加的第一位。
其次,像整数这样的其他数据类型需要更多的位来表示,因此它们将在流中占用更多的空间而不是布尔值。当它们没有在字节边界上对齐时,在同一个流中混合使用不同大小的数据类型会非常棘手。
最后,如果您使用的是Intel x86,那么您的CPU架构就是“小端”,这意味着LSB首先就像您所描述的那样。如果您需要将流中的值存储为big-endian,则需要在代码中添加转换层 - 类似于上面显示的内容,您可以按照所需的顺序一次将一个字节推送到流中。这很烦人,但如果您需要与大端Unix机器人互操作或协议规范可能需要,通常需要这样做。
希望有所帮助!
答案 1 :(得分:1)
我缺少这种设计的原因吗?具有此行为的位流的任何其他实现?有什么设计考虑因素?
我怀疑决定背后有任何重要意义。从技术上讲,只要作者和读者同意订购,它就没关系。
答案 2 :(得分:1)
我同意Elazar的意见。
正如他/她指出的那样,这是一个读者和作者不同意位排序的情况。事实上,它们是不相容的。