C#小端或大端?
在允许我们通过UDP / IP控制硬件的文档中,我发现了以下片段:
在这个通信协议中,DWORD是一个4字节数据,WORD是一个2字节数据,BYTE是一个单字节数据。 存储格式为小端,即4字节(32位)数据存储为:d7-d0,d15-d8,d23-d16,d31-d24; 双字节(16位)数据存储为:d7-d0,d15-d8。
我想知道这是如何转换为C#? 在发送之前是否需要转换内容? 例如,如果我想发送一个32位整数或一个4个字符的string?
C#本身并没有定义字节顺序。 但是,每当你转换为字节,你正在做出select。 BitConverter类有一个IsLittleEndian字段来告诉你它将如何performance,但它没有给出select。 BinaryReader / BinaryWriter也是如此。
我的MiscUtil库有一个EndianBitConverter类,允许你定义字节序; BinaryReader / Writer有类似的等价物。 没有在线使用指南我很害怕,但他们是微不足道的:)
(EndianBitConverter也有一个function,这个function在普通的BitConverter中不存在,就是在一个字节数组中就地进行转换。)
你也可以使用
IPAddress.NetworkToHostOrder(...)
简而言之,int或long。
小端,短的答案(我需要做什么)是“可能不是,但它取决于你的硬件”。 你可以检查:
bool le = BitConverter.IsLittleEndian;
根据这个说法,你可能想要将部分缓冲区翻转。 另外,Jon Skeet 在这里有特定的endian转换器(查找EndianBitConverter)。
请注意,itanium(例如)是big-endian。 大多数英特尔都是小端。
重新具体的UDP / IP …?
您需要了解networking字节顺序以及CPU端位置。
通常,对于TCP / UDP通信,您总是使用htons
函数(以及ntohs
及其相关函数)将数据转换为networking字节顺序。
通常networking顺序是大端,但在这种情况下(出于某种原因!)通信是小端,所以这些function不是很有用。 这一点很重要,因为你不能假设他们已经实现的UDP通信遵循任何其他的标准,如果你有一个大端的体系结构,它也会使生活变得困难,因为你不应该用一种方式来包装所有的东西:-(
但是,如果你来自Intel x86架构,那么你已经是小端,所以只需发送数据而不用转换。
或者您可以使用此代码将BitConverter切换到大端:
typeof (BitConverter).GetRuntimeField("IsLittleEndian").SetValue(null, false);
并切换回小端:
typeof (BitConverter).GetRuntimeField("IsLittleEndian").SetValue(null, true);
我正在使用UDP Multicast打包的数据,我需要重新sortingUInt16八位组,因为我注意到包头(Wireshark)中有一个错误,所以我这样做了:
private UInt16 swapOctetsUInt16(UInt16 toSwap) { Int32 tmp = 0; tmp = toSwap >> 8; tmp = tmp | ((toSwap & 0xff) << 8); return (UInt16) tmp; }
在UInt32的情况下,
private UInt32 swapOctetsUInt32(UInt32 toSwap) { UInt32 tmp = 0; tmp = toSwap >> 24; tmp = tmp | ((toSwap & 0xff0000) >> 8); tmp = tmp | ((toSwap & 0xff00) << 8); tmp = tmp | ((toSwap & 0xff) << 24); return tmp; }
这只是为了testing
private void testSwap() { UInt16 tmp1 = 0x0a0b; UInt32 tmp2 = 0x0a0b0c0d; SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1)); SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1))); Debug.WriteLine("{0}", shb1.ToString()); Debug.WriteLine("{0}", shb2.ToString()); SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2)); SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2))); Debug.WriteLine("{0}", shb3.ToString()); Debug.WriteLine("{0}", shb4.ToString()); }
从哪个输出是这样的:
0B0A: {0} 0A0B: {0} 0D0C0B0A: {0} 0A0B0C0D: {0}
如果你正在分析和性能不重要,考虑这个非常简单的代码:
private static byte[] NetworkToHostOrder (byte[] array, int offset, int length) { return array.Skip (offset).Take (length).Reverse ().ToArray (); } int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0);