题
在代码下面,为什么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.IsLittleEndian
是 false
?它应该是 true
因此行为的,你看到的是正确的。
其他提示
你在一个 little endian 机,在整数储存的最重要的字节的第一个。
BinaryReader假定Little Endian顺序: http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readint64.aspx
你完全肯定,BitConverter.IsLittleEndian是返回的假的?
如果你检查它通过调试-看在你之前使用任何的方法,你可能会得到虚假的,即使它应该返回正确的。
读出来的价值,通过代码是完全确定。也参看 IsLittleEndian领域的报告假的,但它必须Little-Endian?
如果你关心的endian性的字节,乔恩的飞碟写了一类允许你选择endian-为当你做的转换。
这只是:
if (BitConverter.IsLittleEndian == true) Array.Reverse(var);
BitConverter
使用的字节序的机器运行。确保big-endian数量、使用 IPAddress.HostToNetworkOrder
.例如:
IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))