バイト順(Byte Order)とその関連操作について話します.

2768 ワード


http://tech.ddvip.com/2010-02/1267008379145384.html
最近Tokyo Tyrantのために.NETクライアントクラスライブラリを書いています.Tokyo TyrantはTCPプロトコルによるバイナリプロトコルを公開しています.そこで、私たちの仕事は実際にはプロトコルに従ってバイナリデータストリームを送信したり読み取ったりするだけで、面倒ではありません.ただし、ここでは「バイト順」という概念が含まれています.これはコンピュータシステムの構造/オペレーティングシステムなどの授業の基礎ですが、ここで簡単に説明するつもりです.また、NETでは一部のクラスがこのようなデータフローを処理する際の注意事項について少しずつ記録してまとめています.
バイト順(Byte Order)
プログラム間の通信といえば、あくまでデータストリームを送信することです.私たちはバイト(byte)をデータの最小単位と見なします.もちろん、1バイトには8ビット(bit)が含まれています.なぜ多くの友達がbitやbyteとの関係を知らないのか不思議です.一連のbyteを手にすると、それ自体は意味がなく、意味があるのは「バイトを識別する方式」だけです.例えば、同じ4バイトのデータを、1つの32ビットの整数、2つのユニック、または4つのASCII文字と見なすことができます.
同じように、32ビットのCPUでは「字長」が32 bit、つまり4 byteであることを知っています.このようなCPUでは、常に4バイトの配列でメモリを読み出したり書き込みしていますが、この4バイトのデータはどのような順序でメモリに保存されていますか?例えば、今私たちはメモリアドレスaのところにデータ0 x 0 A 0 C 0 Dを書き込みたいですが、この4バイトはそれぞれどのアドレスのメモリに落ちますか?これはバイト順に関する問題です.
各データにはいわゆる「有効ビット」がありますが、その意味は「このデータに使うバイトを表します」ということです.たとえば、32ビットの整数は、その有効なビットが4バイトです.0 x 0 A 0 B 0 C 0 Dにとって、その有効なビットは高いから低いまで0 A、0 B、0 Cおよび0 Dです.ここでは256進数として見ることができます.
大きなバイト順(big endian)とは、その「最上位有効ビット(most significant byte)」を低アドレスに落とした記憶方式を指す.例えば、アドレスaが0 x 0 A 0 B 0 C 0 Dに書き込まれた後、メモリ内のデータは次の通りである.
小さいバイト順では逆です.「最低有効ビット」を低い住所に置いています.たとえば:
私たちがよく使うCPUアーキテクチャについては、Intelなど、AMDのCPUはすべて小さいバイト順を使っていますが、例えばMac OSは以前使っていたPower PCは大きなバイト順を使っています.また、大きなバイト順と小さなバイト順の他に、極めて稀なミドルバイト順があり、2143でデータを保存する(大きなバイト順の1234及び小さなバイト順の4321に対して).
バイト順の詳細については、Wikipedia内のEdianness項目を参照してください.
NETクラスライブラリBinaryWriterとBinaryReader
NETフレームでデータストリームを操作する時、私達はBinaryWriterとBinaryReaderを使って読み書きます.これらの2つのクラスには対応するWriteInt 32またはReadInt 32方法がありますが、バイト順はどのように処理されますか?MSDNから,BinaryReaderが小さなバイト順でデータを読み出すことを知った.これは、
var stream = new MemoryStream(new byte[] { 4, 1, 0, 0 }); 
var reader = new BinaryReader(stream); 
int i = reader.ReadInt32(); // i == 260
これに類似して、自然BinaryWriterも小さなバイト順でデータを書き込みます.
Bit Coverter
BitConverterを使用してbyte配列および32ビットの整数(もちろん他のタイプも含む)を変換する場合もありますが、これはバイト順の操作に関連していますが、それらはどのように処理されますか?BinaryWriterとBinaryReaderの「固定戦略」とは違って、BitConterの行為はプラットフォームに関連しています.
まず、BitConverterには、現在のプラットフォームのバイト順を表しているリードオンリー静的フィールドがあります.私たちは異なるCPUのために異なるNETクラスのライブラリをインストールしますので、NET Reflecttorを通じてこのフィールドを確認したら定数trueに設定されています.次に、BitConverterのそれぞれの便利さは、IsLittleEndanの値によって異なる行動を生じます.例えば、ToInt 32の方法:
public static unsafe int ToInt32(byte[] value, int startIndex) 
{ 
  // ... 
 
  fixed (byte* numRef = &(value[startIndex])) 
  { 
    if ((startIndex % 4) == 0) 
    { 
      return *(((int*)numRef)); 
    } 
    if (IsLittleEndian) 
    { 
      return numRef[0] | (numRef[1] << 8) | (numRef[2] << 16) | (numRef[3] << 24); 
    } 
 
    return (numRef[0] << 24) | (numRef[1] << 16) | (numRef[2] << 8) | numRef[3]; 
  } 
}