BinaryReader.ReadInt64
是小端设计的。从文档中:
BinaryReader 以 little-endian 格式读取此数据类型。
实际上,我们可以查看BinaryReader.ReadInt64
使用 Reflector 的来源。
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
是独立于底层机器架构的小端。
现在,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
与零模八一致,则直接转换是从从 address 开始的八个字节完成的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
。在小端的情况下,缓冲区被解释为小端(因此内存{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
被解释为 long 0x0706050403020100
),在大端的情况下,缓冲区被解释为大端(因此内存{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
被解释为 long 0x0001020304050607
)。所以,BitConverter
这一切都归结为底层机器的字节顺序。我注意到您使用的是 Windows 7 x64 上的英特尔芯片。英特尔芯片是小端的。我注意到在 Reflector 中,静态构造函数的BitConverter
定义如下:
static BitConverter() {
IsLittleEndian = true;
}
这是在我的 Windows Vista x64 机器上。(例如,在 XBox 360 上的 .NET CF 上可能会有所不同。)Windows 7 x64 没有任何不同的理由。因此,你确定BitConverter.IsLittleEndian
是false
吗?它应该是true
,因此您看到的行为是正确的。