質問
以下のコードで、X と Y が直感的に考えた値と異なる値をとるのはなぜですか?
バイト 0 ~ 7 がバッファに書き込まれる場合、結果として得られる Long には同じ順序のバイトが含まれるはずではありませんか?長い値を逆の順序で読んでいるようです。
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);
(.NET 以外にも、この質問に何のタグを付ければよいのかわかりません。)
BitConverter.IsLittleEndian
は誤りです。私のコンピュータがビッグエンディアンである場合、なぜこのようなことが起こるのでしょうか?
- これは Windows 7 64 ビット マシンです
- Intel Core2 クアッド Q9400 2.66 GHz LGA 775 95W クアッドコア プロセッサー モデル BX80580Q9400
- SUPERMICRO MBD-C2SBX+-O LGA 775 インテル X48 ATX インテル マザーボード
このコードの結果 (Jason のコメントに応じて):
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
の設計により、リトルエンディアンであります。ドキュメントから:
BinaryReaderは、リトルエンディアン形式でこのデータ型を読み込みます。
実際には、我々は、反射板を使用して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
を表示することは基本的なマシンアーキテクチャのようリトルエンディアンの独立を読み込みます。
さて、 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
から始まる8バイトから行われていることをゼロモジュロ8と合同であるということです。この場合は、理由は、アライメントの問題の特別に処理されています。コードの行
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
として解釈されるように)リトルエンディアンの場合にバッファがリトルエンディアンとして解釈され、(メモリ{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }
が長い0x0001020304050607
として解釈されるように)ビッグエンディアンの場合にはバッファはビッグエンディアンとして解釈され。だから、BitConverter
のためにそれはすべてのunderylingマシンのエンディアンにまで来ています。私は、Windows 7のx64上のインテルチップにしていることに注意してください。 Intelチップはリトルエンディアンです。私はリフレクターで、BitConverter
の静的コンストラクタは次のように定義されていることに注意します:
static BitConverter() {
IsLittleEndian = true;
}
これは私のWindows Vistaのx64マシン上にあります。 (これは、たとえば、上のXbox 360上の.NET CFを異なる可能性がある)は、Windows 7のx64は任意の異なるものにするための理由はありません。その結果、あなたはBitConverter.IsLittleEndian
がfalse
であることを確信していますか?それはtrue
する必要があるので、あなたが見ている動作は正しいです。
他のヒント
あなたは整数が格納されているリトルエンディアンのマシン、にしています最下位バイト最初ます。
BinaryReaderリトルエンディアンの順序を前提としていますのhttp:/ /msdn.microsoft.com/en-us/library/system.io.binaryreader.readint64.aspxする
あなたはBitConverter.IsLittleEndianはfalseを返していることをCOMPLETELYか?
あなたはそれの方法のうちのいずれかを使用していた前に、あなたは、デバッガウォッチを通してそれを検査した場合は、あなたはそれがtrueを返す場合でもfalseを得る可能性があります。
完全に特定するコードを介して値を読み出します。 IsLittleEndianフィールドが虚偽の報告が、それは少しでなければならないも参照してください。 -Endianですか
、ジョンスキートはあなたが変換を行うときに、エンディアン順序を選択できるようにするクラスを書いています。
を参照してください。 C#リトルエンディアンまたはビッグエンディアンですか
それはちょうどです。
if (BitConverter.IsLittleEndian == true) Array.Reverse(var);
BitConverter
は、それが実行しているマシンのエンディアンを使用しています。ビッグエンディアン数を確保するために、IPAddress.HostToNetworkOrder
を使用しています。たとえばます:
IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))