16進数のバイト列が逆に見える理由
16進数の値をメモリダンプ、バイナリファイル、通信ログなどで確認すると、期待した順番と逆に見えることがあります。たとえば、数値としては0x12345678のはずなのに、バイト列としては78 56 34 12のように表示される場合です。
これはデータが壊れているとは限りません。多くの場合、エンディアン、つまりバイトオーダーの違いが原因です。
この記事の要点
- 16進数のバイト列が逆に見える原因は、Big EndianとLittle Endianの違いであることが多いです。
- 反転するのはビット単位ではなく、通常はバイト単位です。
- メモリダンプ、ファイル解析、通信データを見るときは、どのエンディアンで読むべきかを確認します。
まず確認する例
数値0x12345678を4バイトの値として考えます。Big Endianでは上位バイトから、Little Endianでは下位バイトから順番に並びます。
Big Endian:12 34 56 78
Little Endian:78 56 34 12
このため、メモリ上のバイト列だけを見ると、値が逆向きに保存されているように見えることがあります。ただし、読み込む側が同じエンディアンを前提にしていれば、値そのものは0x12345678として正しく扱われます。
逆に見えるのは「バイト単位」
エンディアン変換でよくある誤解は、数字やビットを1文字ずつ反転してしまうことです。0x12345678をLittle Endianにするとき、87654321にはしません。
正しくは、2桁の16進数を1バイトとして区切り、バイト単位で並び替えます。
12 34 56 78
↓
78 56 34 1216進数では2桁で1バイトを表します。エンディアンを考えるときは、まず2桁ずつ区切って見ることが大切です。
よくある間違い
| 間違い | 例 | 正しい考え方 |
|---|---|---|
| 1文字ずつ反転する | 12345678 → 87654321 | 2桁ずつ区切ってバイト単位で反転する |
| ビット順を反転する | 00010010を逆順にする | 通常のエンディアン変換ではビット順は変えない |
| 何バイトの値か確認しない | 123456をそのまま反転する | 2バイト、4バイト、8バイトなどの単位を確認する |
| 文字列のHEXと数値のHEXを混同する | 31 32 33を数値123と読む | 文字コード由来のHEXか数値由来のHEXか確認する |
特に大切なのは、何バイトの値として扱うかです。2バイトの値と4バイトの値では、並び替える単位が変わります。
2バイト・4バイト・8バイトでの違い
同じ16進数でも、何バイトの値として読むかによって見え方が変わります。
| 幅 | Big Endian | Little Endian |
|---|---|---|
| 2バイト | 12 34 | 34 12 |
| 4バイト | 12 34 56 78 | 78 56 34 12 |
| 8バイト | 01 23 45 67 89 AB CD EF | EF CD AB 89 67 45 23 01 |
エンディアン変換では値全体をバイト単位で並び替えます。途中の1バイトの中身までは反転しません。
メモリダンプで逆に見える場合
メモリダンプでは、CPUが実際にメモリへ保存しているバイト列が表示されます。Little Endianの環境では、4バイト整数0x12345678が78 56 34 12のように見えることがあります。
開発中にデバッガやバイナリエディタで値を見るときは、表示されているものがメモリ上の並びなのか、数値として解釈された表示なのかを分けて考えます。
ファイル解析で確認するポイント
バイナリファイルを読む場合、ファイル形式ごとにエンディアンが決まっていることがあります。たとえば4バイトの領域が78 56 34 12だった場合、Little Endianとして読めば数値は0x12345678です。一方、Big Endianとして読めば0x78563412になります。
同じバイト列でも、エンディアンの前提が違うと数値が変わります。ファイル仕様書やデータフォーマットの説明で、Big EndianなのかLittle Endianなのかを確認することが重要です。
通信データで確認するポイント
通信プロトコルでは、ネットワークバイトオーダーとしてBig Endianが使われることがあります。一方、PCやサーバー内部ではLittle EndianのCPUがよく使われます。そのため、内部で使っている数値を通信データとして送るときに、エンディアン変換が必要になることがあります。
- プロトコル上のバイトオーダーは何か
- ログに表示されているのは送信されたバイト列そのものか
- 受信側がどのエンディアンで数値に変換しているか
- 2バイト、4バイト、8バイトのどの単位で読むべきか
この確認をしないまま数値を読むと、本来の値とまったく違う数値に見えることがあります。
文字列のHEXとは区別する
エンディアンは、主に複数バイトの数値をどう並べるかの話です。一方、文字列をHEXで表した場合は、文字コードのバイト列として扱います。
文字列1234をASCIIでHEXにすると31 32 33 34です。これは数値0x1234とは別物です。
数値のエンディアン変換をしているのか、文字列の文字コードを確認しているのかを混同しないようにしましょう。
ツールで確認する方法
エンディアン変換ツールを使うと、16進数のバイト列をBig EndianとLittle Endianで確認できます。使うときは、次の順番で確認すると分かりやすくなります。
- 16進数を2桁ずつ区切る
- 何バイトの値として扱うか確認する
- Big Endianの並びを確認する
- Little Endianの並びを確認する
- 10進数や2進数としての解釈も確認する
特に0x12345678、0x00000001、0xFF000000のような値で試すと、バイト順の違いが見えやすくなります。
よくある質問
16進数を逆にすればLittle Endianになりますか?
1文字ずつ逆にするのではありません。16進数は2桁で1バイトを表すため、通常は2桁ずつ区切ってバイト単位で並び替えます。
エンディアン変換ではビットも反転しますか?
通常は反転しません。エンディアンは複数バイトの値を保存・送信するときのバイトの並び順を指し、各バイト内のビット順を逆にするものではありません。
12345678と78 56 34 12は同じ値ですか?
前提によります。78 56 34 12をLittle Endianの4バイト値として読む場合は、数値として0x12345678になります。Big Endianとして読む場合は0x78563412になります。
何バイト単位で変換すればよいですか?
元データの仕様によります。2バイト整数、4バイト整数、8バイト整数など、データ型やファイル仕様に合わせて確認する必要があります。
文字列のHEXにもエンディアンは関係しますか?
通常の文字列HEXでは、文字コードのバイト列をそのまま確認することが多く、数値のエンディアンとは分けて考えます。ただしUTF-16やUTF-32ではBOMやバイト順が関係する場合があります。