BinaryReader.ReadInt64
по порядку имеет младший порядок. Из документации:
BinaryReader читает этот тип данных в формате с прямым порядком байтов.
Фактически, мы можем проверить источник на 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
читается как little-endian независимо от базовой архитектуры машины.
Теперь, BitConverter.ToInt64
предполагается, чтобы уважать порядковый номер вашей базовой машины. В Reflector мы видим
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-компилятору справиться с этой проблемой. На машине с прямым порядком байтов ldind.i8
загрузит старшие адреса в более значимые биты, а на машине с прямым порядком байтов ldind.i8
загрузит старшие адреса в менее значимые байты. Следовательно, в этом случае порядок байтов обрабатывается правильно.
В другом случае вы можете видеть, что есть явная проверка статического свойства BitConverter.IsLittleEndian
. В случае с прямым порядком байтов буфер интерпретируется как младший (так что память { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
интерпретируется как длинный 0x0706050403020100
), а в случае с большим порядком байтов буфер интерпретируется как большой (так что память интерпретируется как длинный 0x0001020304050607
). Таким образом, для BitConverter
все сводится к порядку работы машины-подложки. Хочу заметить, что вы используете чип Intel на Windows 7 x64. Чипы Intel имеют младший порядок. Я отмечаю, что в Reflector статический конструктор для BitConverter
определяется следующим образом:
static BitConverter() {
IsLittleEndian = true;
}
Это на моем компьютере с Windows Vista x64. (Это может отличаться, скажем, от .NET CF на XBox 360.) Нет никаких причин для Windows 7 x64 быть другой. Следовательно, вы уверены, что BitConverter.IsLittleEndian
- это false
? Это должно быть true
, и поэтому поведение, которое вы видите, является правильным.