【问题标题】:C# binary strings respecting endianess尊重字节顺序的 C# 二进制字符串
【发布时间】:2021-07-25 15:32:02
【问题描述】:

我满足了查看某些数据(tcp 数据包、文件、某些数据结构的二进制序列化......)的二进制/十六进制表示的需要,似乎我总是偶然发现与字节序和相同的问题每次写字符串转换的字节顺序。

关于这个话题已经有其他问题了,但我的具体实现似乎有些问题。

我尝试自己编写一些函数来将任何字节/字节数组转换为二进制字符串(以 8 个块为单位,因为包含的函数只给出“使用的位”),但问题是我得到了不同的结果。而且我不知道在哪里需要注意底层系统的字节序。

 class Program
    {
        static void Main(string[] args)
        {
           
            //ushort x = 13;
            ushort x = 3328;
            string res = ToBinaryString(x);
            string res2 = ToBinaryString(BitConverter.GetBytes(x));
            Console.WriteLine("res:  " + res + "\r\n" + "res2: " + res2);
        }

        public static string ToBinaryString(byte v)
        {
            return Convert.ToString(v, 2).PadLeft(8, '0');
        }

        public static string ToBinaryString(byte[] v)
        {
            string[] strArr = new string[v.Length];
            for(int i = 0; i < v.Length; i++)
            {
                strArr[i] = ToBinaryString(v[i]);
            }
            return string.Join("", strArr);
        }

        public static string ToBinaryString(ushort v)
        {
            return Convert.ToString(v, 2).PadLeft(16, '0');
        }
    }
}

意外的不同输出是:

res:  0000110100000000
res2: 0000000000001101

所以我有点困惑,因为到目前为止,我认为这两种方法会返回相同(正确)的结果,而不是不同的结果。

值得注意的是:我在 Windows 开发机器上。

【问题讨论】:

  • 您在寻找IsLittleEndian吗?但与其明确检查字节顺序,不如使用 NetworkToHostOrder 之类的东西。
  • 没有。目前我还没有检查 IsLittleEndian 但我已经在考虑在哪里使用它(在 ToBinaryString(ushort) 或 toBinaryString(byte[]) 方法中。由于这些方法与网络无关,我不确定 NetworkToHostOrder 是否可用对我来说现在。但是当我使用调试TCP数据包的功能时,肯定会出现。
  • @monty 需要注意的是,BitConverter.GetBytes 方法返回的数组中的字节顺序取决于机器是小端还是大端。 IE。 byteArray[0] 包含 little-endian 机器上的最低有效字节和 big-endian 机器上的最高有效字节。但我的回答只尊重小端。 docs.microsoft.com/en-us/dotnet/api/…

标签: c# binary endianness


【解决方案1】:

好的。

下面的代码与一个little-endian机器有关。我没有对照大端法检查它。根据MicrosoftBitConverter.GetBytes 将数字的最低有效字节写入小端机器上 byteArray 的第一个元素。然后它将下一个更重要的字节写入 byteArray 的第二个元素,依此类推。

BitConverter.GetBytes 产生的字节数组元素的顺序取决于机器字节序。

这就是你的小端机器中发生的事情。

3328 在十六进制视图中是 D00。 00 是最低有效字节,D 是最高有效字节。 让我们看看当您将整数传输到 BitConverter.GetBytes(x) 时会发生什么。

它将您的数字转换为数组,其中第一个成员为 00,第二个成员为 D。 (v[0] = 0; v[1] = D)

让我们看看发生了什么

带字节数组的ToBinaryString方法

    string[] strArr = new string[v.Length]

原来是 strArr = 新刺[2]

然后

    for(int i = 0; i < v.Length; i++)

原来是 for(int i = 0; i

在第一关,你得到

    strArr[0] = ToBinaryString(v[0]);

=> strArr[0] = "00000000"// 因为你处理的是一个纯零值。

在第二次通过时,你得到

    strArr[0] = ToBinaryString(v[1]);

=>

    Convert.ToString(D, 2)

=> 1101

    1101.PadLeft(8, '0')

=>

00001101

现在我们来看看

    string.Join("", strArr)

就是这样

v[0] + v[1] = "00000000" + "00001101"

即 它返回 0000000000001101

试试

    public static string ToBinaryString(byte[] v)
    {
        string[] strArr = new string[v.Length];
        for(int i = v.Length, j = 0; i > 0; i--, j++)
        {
            strArr[i-1] = ToBinaryString(v[j]);
        }
        return string.Join("", strArr);
    }

res: 0000110100000000 res2: 0000110100000000

问候。

【讨论】:

  • string.Join("", strArr) 使用从最小索引到最大索引的数组成员从左到右形成一个字符串。在位置数字系统中,包括十六进制和十进制,我们从左到右形成数字,最左边的整数位最大。所以必须考虑到处理字节数组。字符串值中最左边的字节匹配字节数组中索引最大的元素。
  • 非常感谢您的详细解释。我特别感谢一开始对十六进制版本的交叉检查。
  • 事实上,我认为我的代码是正确的,不需要向后遍历字节循环。所以如果,那么另一种方式是错误的。
  • 我不明白你在说什么代码行。请说得更具体些。
  • 我用维基百科的一个例子再次测试和调试: int 16_909_060 de.wikipedia.org/wiki/Byte-Reihenfolge 这个例子的字节(它们的值)从 1 到 4 编号,调试器显示它们存储为 4 3 2 1 含义正确的二进制字符串将是:00000100 00000011 00000010 00000001。我使用 for (int i=0, i 创建
猜你喜欢
  • 1970-01-01
  • 2012-10-20
  • 2016-02-29
  • 2020-05-06
  • 2015-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多