質問

以下のコードで、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.IsLittleEndianfalseであることを確信していますか?それは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))
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top