C#从4个字节生成大端序的ulong

19

我正在尝试在C#中将一个4字节数组转换为ulong类型。我目前正在使用以下代码:

atomSize = BitConverter.ToUInt32(buffer, 0);

这个byte[4]包含了以下内容:

0 0 0 32

然而,这些bytes采用的是Big-Endian顺序。有没有一种简单的方法将这个Big-Endian的ulong转换成Little-Endian的ulong?

7个回答

24

我认为Jon Skeet的MiscUtil库中的EndianBitConverter(nuget link)可以实现你想要的功能。

你也可以使用位移操作来交换位:

uint swapEndianness(uint x)
{
    return ((x & 0x000000ff) << 24) +  // First byte
           ((x & 0x0000ff00) << 8) +   // Second byte
           ((x & 0x00ff0000) >> 8) +   // Third byte
           ((x & 0xff000000) >> 24);   // Fourth byte
}

使用方法:

atomSize = BitConverter.ToUInt32(buffer, 0);
atomSize = swapEndianness(atomSize);

1
谢谢,也许你可以逐行展示一下你正在做什么?那将是很棒的,我从未使用过位移操作直到现在。 - WesleyE
1
@WesleyE:我已经重写了它,使其更清晰。它一次处理一个字节,屏蔽掉8位,然后将它们移动到新位置。四个字节然后相加以得出结果。如果您不理解什么是位移,请参考这个问题+答案:https://dev59.com/Q3VC5IYBdhLWcg3w7V73 - Mark Byers
1
每次移除and操作并转换为字节会更快。 - usr
您可以通过Nuget安装MiscUtil: https://www.nuget.org/packages/JonSkeet.MiscUtil/ - Yves M.

10

在 .net core (>= 2.1) 中,你可以使用这个代替:

BinaryPrimitives.ReadUInt32BigEndian(buffer);
那样做,你就可以确定读取的字节顺序方式。

文档

如果你想知道它是如何工作的,它在这里实现了

编辑:正如评论中@smkanadl提到的那样,似乎你也可以通过安装System.Memory包在.net framework中使用此API。


最佳解决方案,因为它不需要位操作或缓冲区的额外迭代(Array.Reverse()),也不需要额外的分配(buffer.Reverse().ToArray())。 - Good Night Nerd Pride
这个解决方案不仅限于 .net core。你可以简单地安装 System.Memory nuget 包。 - smkanadl

7

System.Net.IPAddress.NetworkToHostOrder(atomSize);会翻转你的字节。


3
不一定。如果您的主机已经是大端序,那么就不会进行任何更改。 - Jeff Mercado
不要紧,Jeff。重点是,如果系统已经是大端字节序,那么BitConverter将按照BigEndian的方式读取它,不需要任何更改。不幸的是,如果你正在处理包含数十万个数据的文件,使用这个函数或Jon的转换可能会导致严重的性能损失。如果是这种情况,那么你应该采用Mark Byers的建议。提高速度的唯一方法就是制作CPU特定的函数,即x86具有BSWAP汇编指令,比位移操作快得多。这个函数对于数据包处理来说非常好。 - Rahly

5
我建议使用Mono的DataConvert,它就像是具有类固醇作用的BitConverter。它允许您直接读取大端字节数组,并且在BitConverter上有大幅度的改进。
源代码的直接链接在这里

1
固定的源代码位置(看起来它们已经迁移到了GitHub :D) - Callum Rogers

4
BitConverter.ToUInt32(buffer.Reverse().ToArray(), 0)

不需要吗?

不完全正确,你需要在那里加上一个 ToArray() 调用。 - Jeff Mercado
不完全相同,如果您的缓冲区大于4,则最后4个字节将被交换。应该使用0和buffer.Length-4。 - Rahly

2

这可能有点老了,但我很惊讶还没有人提出这个最简单的答案,只需要一行代码...

// buffer is 00 00 00 32
Array.Reverse(buffer);
// buffer is 32 00 00 00
atomSize = BitConverter.ToUInt32(buffer, 0);

我正在使用它来比较在C#(小端)生成的校验和和在Java(大端)生成的校验和。


不是同一件事。如果缓冲区是00 00 00 32 54,则反转后的缓冲区为54 32 00 00 00,因此ToUInt32将不会给您值32。如果您的缓冲区始终为长度4,则这将完美运行。要使其适用于不同的长度,您需要在Reverse之后使用Length-4而不是0。 - Rahly
2
这个话题是“C#从4个字节获取大端ulong”,这是我对问题的具体回答,我从未说过这是每种情况的解决方案,但对于定义好的数字数据类型(16位、32位、64位等),只要目标字节数组有相同数量的字节,它就足够了。 - IaguCool

0
firstSingle = BitConverter.ToSingle(buffer,0);
secondSingle = BitConverter.ToSingle(buffer,2); 

var result = BitConverter.ToUInt32(BitConverter.GetBytes(secondSingle).Concat(BitConverter.GetBytes(firstSingle).ToArray());

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