在代码下面,为什么X和Y采取不同的价值观,比什么我会觉得直觉?

如果字节0-7写入缓冲区,不应该得到的长期有字节的顺序相同?这就像是读书长值相反的顺序。

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);

(我不知道该怎么签这个问题,超出了公正的。网。)


BitConverter.IsLittleEndian

是错误的。如果我的计算机big endian,为什么这种事发生?

  • 这是一个Windows7 64位机
  • 英特尔的酷睿2四Q9400 2.66GHz LGA775 95W四核处理器型号BX80580Q9400
  • SUPERMICRO MBD-C2SBX+-O LGA775英特尔X48度的英特尔的主板

结果这代码(在响应他的评论):

byte[] buffer = new byte[] { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
long y = BitConverter.ToInt64(buffer, 1);
Console.WriteLine(BitConverter.IsLittleEndian);
Console.WriteLine(y);

结果是:

False
506097522914230528
有帮助吗?

解决方案

BinaryReader.ReadInt64 是little endian通过设计。从文件:

BinaryReader读取这些数据的类型在little-endian格式。

事实上,我们可以检查来源 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);
}

显示 BinaryReader.ReadInt64 如little endian独立的基础机构。

现在, BitConverter.ToInt64 是假定尊重的字节序的基础机。在反射器,我们可以看到

public static unsafe long ToInt64(byte[] value, int startIndex) {
    // argument checking elided
    fixed (byte* numRef = &(value[startIndex])) {
        if ((startIndex % 8) == 0) {
            return *(((long*) numRef));
        }
        if (IsLittleEndian) {
            int num = (numRef[0] << 0x00) |
                      (numRef[1] << 0x08) |
                      (numRef[2] << 0x10) |
                      (numRef[3] << 0x18);
            int num2 = (numRef[4] << 0x00) |
                       (numRef[5] << 0x08) |
                       (numRef[6] << 0x10) |
                       (numRef[7] << 0x18);
            return (((long) ((ulong) num)) | (num2 << 0x20));
        }
        int num3 = (numRef[0] << 0x18) |
                   (numRef[1] << 0x10) |
                   (numRef[2] << 0x08) |
                   (numRef[3] << 0x00);
        int num4 = (numRef[4] << 0x18) |
                   (numRef[5] << 0x10) |
                   (numRef[6] << 0x08) |
                   (numRef[7] << 0x00);
        return (((long) ((ulong) num4)) | (num3 << 0x20));
}

所以我们在这里看到的是,如果 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编译器处理这一问题。在little-endian机, ldind.i8 将载入更高的地址进入更加显着的位和在big-endian机 ldind.i8 将载入更高的地址进入较不显着的字节。因此,在这种情况下,字节序是正确的处理。

在其他情况下,可以看到,有一个明确的检查的静态的酒店 BitConverter.IsLittleEndian.在little endian缓解释为little endian(以便存储器 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 } 是解释为长 0x0706050403020100),并在情况下的big endian缓解释为big endian(以便存储器 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 } 是解释为长 0x0001020304050607).因此,对于 BitConverter 这一切都归结为一个字节序的underyling机。我注意到你在英特尔芯片上的Windows7 64.英特尔的芯片是小端。我注意到,在反射器,静态的构造 BitConverter 定义如下:

static BitConverter() {
    IsLittleEndian = true;
}

这是在我的Windows Vista64机。(它可能有所不同,说.净CF在一个XBox360.) 没有任何理由为Windows7 64任何不同。因此,你确定 BitConverter.IsLittleEndianfalse?它应该是 true 因此行为的,你看到的是正确的。

其他提示

你在一个 little endian 机,在整数储存的最重要的字节的第一个。

你完全肯定,BitConverter.IsLittleEndian是返回的假的?

如果你检查它通过调试-看在你之前使用任何的方法,你可能会得到虚假的,即使它应该返回正确的。

读出来的价值,通过代码是完全确定。也参看 IsLittleEndian领域的报告假的,但它必须Little-Endian?

如果你关心的endian性的字节,乔恩的飞碟写了一类允许你选择endian-为当你做的转换。

看看 C#little endian或big endian?

这只是:

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

BitConverter 使用的字节序的机器运行。确保big-endian数量、使用 IPAddress.HostToNetworkOrder.例如:

IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top