私は最近、BitConverter がどのように機能するかを調べており、他の SO の質問を読んだことから、開始インデックスが変換される型のサイズで割り切れる場合、ポインターをキャストできる場所に「近道」を取ることを読みました。変換先の型へのポインターへのインデックスの byte を参照し、逆参照します。
例として ToInt16 のソース:
public static unsafe short ToInt16(byte[] value, int startIndex) {
if( value == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
}
if ((uint) startIndex >= value.Length) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
}
if (startIndex > value.Length -2) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
}
Contract.EndContractBlock();
fixed( byte * pbyte = &value[startIndex]) {
if( startIndex % 2 == 0) { // data is aligned
return *((short *) pbyte);
}
else {
if( IsLittleEndian) {
return (short)((*pbyte) | (*(pbyte + 1) << 8)) ;
}
else {
return (short)((*pbyte << 8) | (*(pbyte + 1)));
}
}
}
}
私の質問は、マシンのエンディアンに関係なくなぜこれが機能するのか、データが整列されていないときに同じメカニズムを使用しないのはなぜですか?
明確にする例:
ビッグエンディアン形式であることがわかっているバイトがいくつかbuffer
あり、たとえばインデックス5の配列から短い値を読み取りたいと思います。また、私のマシンはWindowsであるため、リトルエンディアンを使用していると仮定します。
バイトの順序をリトルエンディアンに切り替えることで、BitConverter を次のように使用します。
BitConverter.ToInt16(new byte[] { buffer[6], buffer[5] })
コードがショートカットを取ると仮定すると、それは私が望むことをするでしょう.提供された順序でバイトをキャストし、値を返すだけです. しかし、そのショートカット コードがなければ、バイト オーダーが再び逆になり、間違った値が返されるのではないでしょうか? または、代わりに行った場合:
BitConverter.ToInt16(new byte[] { 0, buffer[6], buffer[5] }, 1)
インデックスが 2 で割り切れないため、間違った値が得られませんか?
別の状況:
すでにリトルエンディアン形式で抽出したいが、奇数のオフセットから始まる短いバイト配列があったとします。BitConverter.IsLittleEndian が true であり、インデックスが整列されていないため、BitConverter の呼び出しでバイトの順序が逆になり、誤った値が返されることはありませんか?