BinaryReader.ReadInt64
Little-Endian ist konstruktionsbedingt. Aus der Dokumentation:
BinaryReader liest diesen Datentyp im Little-Endian-Format.
In der Tat können wir die Quelle für BinaryReader.ReadInt64
mit Reflektor überprüfen.
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);
}
Zeigt, dass BinaryReader.ReadInt64
so wenig Endian unabhängig von der zugrunde liegenden Maschinenarchitektur liest.
Jetzt sollte BitConverter.ToInt64
die Endianz Ihrer zugrunde liegenden Maschine respektieren. In Reflector können wir
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));
}
So sehen, was wir hier sehen, ist, dass, wenn startIndex
kongruent zu Null modulo acht, die eine direkte Besetzung von acht Bytes ab Adresse erfolgt numRef
. Dieser Fall wird speziell aufgrund von Ausrichtungsproblemen behandelt.Die Codezeile
return *(((long *) numRef));
sich direkt in
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
So sehen wir in diesem Fall, dass der Schlüssel ist die ldind.i8
Anweisung. Die CLI ist agnostisch bezüglich der Endianität der zugrunde liegenden Maschine. Dadurch kann der JIT-Compiler dieses Problem behandeln. Auf einer Little-Endian-Maschine lädt ldind.i8
höhere Adressen in höherwertige Bits und auf einer Big-Endian-Maschine lädt ldind.i8
höhere Adressen in weniger signifikante Bytes. Daher wird in diesem Fall die Endiannität richtig gehandhabt. Im anderen Fall können Sie sehen, dass die statische Eigenschaft BitConverter.IsLittleEndian
explizit überprüft wird. Im Fall von Little Endian wird der Puffer als Little Endian interpretiert (so dass der Speicher { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
als Long 0x0706050403020100
interpretiert wird) und im Fall von Big Endian wird der Puffer als Big Endian interpretiert (so dass der Speicher { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
als Long 0x0001020304050607
interpretiert wird) . Also, für BitConverter
kommt es auf die Endianness der Underinging Maschine an. Ich stelle fest, dass Sie auf einem Intel-Chip unter Windows 7 x64 sind. Intel-Chips sind Little Endian. Ich nehme zur Kenntnis, dass in Reflektor, der statische Konstruktor für BitConverter
wie folgt definiert ist:
static BitConverter() {
IsLittleEndian = true;
}
Dies ist auf meinem Windows Vista x64-Maschine. (Es könnte sich beispielsweise bei .NET CF auf einer XBox 360 unterscheiden.) Es gibt keinen Grund dafür, dass Windows 7 x64 anders ist. Sind Sie also sicher, dass BitConverter.IsLittleEndian
false
ist? Es sollte true
sein und daher ist das Verhalten, das Sie sehen, korrekt.
Added-Tag für Sie :) – spender
Können Sie die Spezifikationen der Maschine (Prozessor, mb, O/S) geben suchen? – GrayWizardx
Dies ist ein Intel Core 2, Windows 7. Ich sollte auch hinzufügen, dass BitConverter.IsLittleEndian false zurückgibt. – Amy