C#中字节和BitArray的位顺序问题

7
我正试图理解字节序和位序。 编辑:评论中指出,字节序与我的问题无关,但我仍然将其放在这里以保证完整性。至少没有人反驳我的“定义”。 目前我所学到的:如果一个值(例如一个字)由多个字节组成(字:2个字节),那么有两种不同的方式可以在连续的内存块中保存该值。假设我们有一个十进制值为43210(0xA8CA,1010100011001010)。
  • BigEndian (first) saves the byte which would have a greater effect on the values magnitude at the lower address, a bit like we write normal arabic numbers.

    Memory address |  1000  |  1001  
    ---------------|--------|---------
    Bytes          |   A8   |   CA
    
  • LittleEndian (first) saves the byte which would have a smaller effect on the values magnitude at the lower address

    Memory address |  1000  |  1001  
    ---------------|--------|---------
    Bytes          |   CA   |   A8
    

这个正确吗?

我学到的第二件事是,在内存中保存一个字节的位有两种不同的方式(使用43210和BigEndian),请注意:

  • Most significant bit (first/left) saves, analoguos BigEndian for bytes, the bits having the greatest impact on the values magnitude first in memory, again: as we write our arabic numbers.

    Memory address |  1000                         |  1001  
    Bit values     |128|64 |32 |16 |8  |4  |2  |1  |128|64 |32 |16 |8  |4  |2  |1  |
    --------------------------------------------------------------------------------
    Bits           | 1   0   1   0   1   0   0   0 | 1   1   0   0   1   0   1   0
    
  • Least significant bit (first/left) reverses the order of bits within a byte, so the bit differentiating between an even and uneven number comes first

    Memory address |  1000                         |  1001  
    Bit values     |1  |2  |4  |8  |16 |32 |64 |128|1  |2  |4  |8  |16 |32 |64 |128|
    --------------------------------------------------------------------------------
    Bits           | 0   0   0   1   0   1   0   1 | 0   1   0   1   0   0   1   1   
    

这也是正确的吗?

下面是我的场景和问题:我通过网络接收数据。协议(Modbus)规定了数据传输是BigEndian,当位被返回并包装在字节中时,MSB位于左侧,LSB位于右侧。我使用C #、.Net 4.5进行编程。

在许多情况下,我使用BitConverter类来检查系统的字节顺序(BitConverter.IsLittleEndian),以正确地通过我的NetSocket传递字值。

    public static byte[] CorrectEndianess(byte[] in_byteArray)
    {
        if (BitConverter.IsLittleEndian)
            return in_byteArray.Reverse().ToArray();
        else return in_byteArray;
    }

当我收到一个包含8个位表示8个线圈(或输入)状态的字节时,所有操作都会停止。根据Modbus协议的定义,它提供以下内容(例如):

    Coil No. (example) | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 |
    -------------------|---------------------------------------|
    Bits               |MSB                                 LSB|
    Example values     | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 1  |

在调试器中,包含此信息的byte显示为值“1”,这很好。然而,我需要将每个单独的位作为布尔值处理。C#提供了BitArray类,我可以传递字节并返回一个bool[],非常适合我的需求。

    BitArray ba = new BitArray(new byte[1] { my_byte_which_is_of_value_1 });

如果我打印BitArrays数组,ba[0]包含值true,其余的为false。所以我认为BitArray认为单个字节是LSB(最低有效位)优先的。这很奇怪,因为它破坏了剩余位的处理,这需要(例如)ba[7]true
长话短说,这里是我的主要问题:
如何检查在BitArraybyte中假定哪种位顺序,以便我始终知道我的LSB和MSB在哪里?
附注:在从右到左的语言中书写的数字是否为BigEndian?

2
字节序不会影响单个字节内的位顺序。BitArray按照其定义工作:每个字节的最低有效位表示最低索引值:“bytes [0]&1”表示位0,“bytes [0]&2”表示位1,“bytes [0]&4”表示位2,依此类推。 http://msdn.microsoft.com/en-us/library/x1xda43a%28v=vs.110%29.aspx - Alex F
所以,看起来你试图处理字节序,尝试从Modbus读取单个字节有点过度。除非协议发送字或双字,否则就直接使用这些字节。 - Alex F
你的第一条评论:啊,我应该仔细看看。所以ba[0]始终是最低有效位(LSB)吗?你的第二条评论:如果我只返回一个字节的数据(这是一个有效的用例),并且必须访问该字节的位,我不认为这是过度设计。 - lhiapgpeonk
我的意思是:当你读取单个字节时,字节序与之无关。只有在读取字、双字和更大的数字时,你才需要考虑字节序。同样,单个字节内的位顺序不受影响(除非通信协议使用了反转的位顺序,在文档中应该有说明)。要访问位,可以使用BitArray或按位操作 - 这是你的选择。 - Alex F
好的,我在问题中提到“Endian”只是为了完整性,因为有两种组合方式。你说得对,字节顺序不是单字节问题的一部分。 - lhiapgpeonk
2个回答

0

好的,我不需要确定远程系统的字节序,我知道它想要什么字节序并返回什么字节序。此外,您提供的函数很有趣,但是由于我想以正确的顺序从字节中读取单个位,所以它们在这里没有用处,因为它们只适用于整数(从字转换到长整型)。 - lhiapgpeonk

0

现在,在仅有几条评论之后,我得到了我正在寻找的答案。如果我看得更仔细,我本来会自己解决问题的。

正如@Alex Farber指出的那样,MSDN说明在BitArray中LSB具有最低索引。我在这里也找到了这个答案:https://dev59.com/qWox5IYBdhLWcg3wpV3F#9066924


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接