在.NET中反转字节顺序

在.NET中反转字节顺序,.net,endianness,.net,Endianness,在下面的代码中,为什么X和Y的值与我直观的想法不同 如果将字节0-7写入缓冲区,那么产生的long不应该具有相同顺序的字节吗?它就像是在以相反的顺序读取长值 x 0x0706050403020100 long y 0x0706050403020100 long z 0x0001020304050607 long MemoryStream ms = new MemoryStream(); byte[] buffer = new byte[] { 0x00, 0

在下面的代码中,为什么X和Y的值与我直观的想法不同

如果将字节0-7写入缓冲区,那么产生的long不应该具有相同顺序的字节吗?它就像是在以相反的顺序读取长值

x    0x0706050403020100    long
y    0x0706050403020100    long
z    0x0001020304050607    long

MemoryStream ms = new MemoryStream();
byte[] buffer = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
ms.Write(buffer, 0, buffer.Length);
ms.Flush();
ms.Position = 0;

BinaryReader reader = new BinaryReader(ms);
long x = reader.ReadInt64();
long y = BitConverter.ToInt64(buffer, 0);
long z = BitConverter.ToInt64(buffer.Reverse<byte>().ToArray<byte>(), 0);

byte[] xbytes = BitConverter.GetBytes(x);
byte[] ybytes = BitConverter.GetBytes(y);
byte[] zbytes = BitConverter.GetBytes(z);
这是错误的。如果我的电脑是big endian,为什么会发生这种情况

  • 这是一台Windows 7 64位计算机
  • 英特尔Core2四核Q9400 2.66GHz LGA 775 95W四核处理器型号BX80580Q9400
  • 超级微型MBD-C2SBX+-O LGA 775英特尔X48 ATX英特尔主板
此代码的结果(回应Jason的评论):

结果:

False
506097522914230528

您在一台计算机上,整数首先存储在最低有效字节。

BinaryReader采用较小的尾端顺序:

如果您关心字节的尾端顺序,Jon Skeet编写了一个类,允许您在进行转换时选择尾端顺序

参见

是设计上的小端点。从文件中:

BinaryReader以little-endian格式读取此数据类型

事实上,我们可以使用Reflector检查源代码中的
BinaryReader.ReadInt64

public virtual long ReadInt64() {
    this.FillBuffer(8);
    uint num = (uint) (((this.m_buffer[0] |
              (this.m_buffer[1] << 0x08)) |
              (this.m_buffer[2] << 0x10)) |
              (this.m_buffer[3] << 0x18));
    uint num2 = (uint) (((this.m_buffer[4] |
               (this.m_buffer[5] << 0x08)) |
               (this.m_buffer[6] << 0x10)) |
               (this.m_buffer[7] << 0x18));
    return (long) ((num2 << 0x20) | num);
}
因此,我们在这里看到的是,如果
startIndex
与零模八相等,则直接从地址
numRef
开始的八个字节进行强制转换。由于对齐问题,本案例专门处理。代码行

return *(((long *) numRef));
直接翻译成

    ldloc.0      ;pushes local 0 on stack, this is numRef
    conv.i       ;pop top of stack, convert to native int, push onto stack
    ldind.i8     ;pop address off stack, indirect load from address as long
    ret          ;return to caller, return value is top of stack
因此我们看到,在本例中,键是
ldind.i8
指令。CLI不知道底层计算机的终结性。它让JIT编译器处理这个问题。在小端机器上,
ldind.i8
将把较高的地址加载到较高的有效位,而在大端机器上,
ldind.i8
将把较高的地址加载到较低的有效位。因此,在这种情况下,endianness被正确处理

在另一种情况下,您可以看到对静态属性
BitConverter.IsLittleEndian
进行了显式检查。在小端数的情况下,缓冲区被解释为小端数(这样内存
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}
被解释为长
0x07060504030100
),在大端数的情况下,缓冲区被解释为大端数(这样内存
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}
被解释为长
0x0001020304050607
)。因此,对于
位转换器
来说,这一切都取决于欠旋转机器的端部。我注意到您使用的是Windows 7 x64上的英特尔芯片。英特尔芯片是小端的。我注意到,在Reflector中,
位转换器的静态构造函数定义如下:

static BitConverter() {
    IsLittleEndian = true;
}

这是在我的Windows Vista x64计算机上。(比如说,在XBox 360上的.NET CF上可能会有所不同。)Windows 7 x64没有任何不同的理由。因此,您确定
BitConverter.IsLittleEndian
false
?它应该是
true
,因此您看到的行为是正确的。

您完全确定BitConverter.IsLittleEndian返回false吗

如果在使用它的任何方法之前通过调试器监视对其进行检查,那么即使它应该返回true,也可能会得到false

通过代码读取值以完全确定。 另请参见

它只是:

if (BitConverter.IsLittleEndian == true) Array.Reverse(var);

位转换器
使用它所运行的机器的端度。要确保使用大端数字,请使用
IPAddress.HostToNetworkOrder
。例如:

IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))

为您添加了搜索标签:)您能给出机器的规格(处理器、mb、O/S)吗?这是一个Intel Core 2,Windows 7。我还应该补充一点,BitConverter.IsLittleEndian返回false。您可以执行以下操作吗:
byte[]buffer=new byte[]{0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};长y=位转换器.ToInt64(缓冲区,1)
并报告
y
的值。请注意,
buffer
比您给出的定义多了一个字节。我无法访问
BitConverter.IsLittleEndian
为false的机器。杰森:我在罚单的编辑2中回答了你的问题。作为一个非.NET人员,我对这个问题感到惊讶。我本来希望.NET能像Java一样将程序员与endianness隔离开来。机器的endianness是不相关的,CLI假设endianness很小,但事实并非如此。Java也不例外。颠倒字节顺序太贵了。最近没什么问题,little endian赢了。BitConverter.IsLittleEndian返回False这是我在stackoverflow上找到的最有用的答案。感谢您一直深入了解IL说明的行为。我完全搞不懂为什么某段代码在显式endian更正发生之前工作。那么有没有办法强制读取反转数组(发出前导零,反转后变为尾随零)。鉴于字节通常来自定义了规格的文件,我一直不明白为什么这些转换必须依赖于机器的端度,而不是,你知道,一个布尔参数……关于为什么这一部分会有用的任何解释?我也很好奇这一点。这段代码似乎解决了我遇到的问题,但我想确定它实际上做了什么。
static BitConverter() {
    IsLittleEndian = true;
}
if (BitConverter.IsLittleEndian == true) Array.Reverse(var);
IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))