差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン | |||
programming:バイトオーダーの変換_バイトスワップ [2018-06-29 10:23] Decomo |
programming:バイトオーダーの変換_バイトスワップ [2021-03-05 09:32] (現在) Decomo |
||
---|---|---|---|
行 5: | 行 5: | ||
バイナリデータを扱うプログラムを書く上で、避けて通る事の出来ないバイトオーダーの問題。 | バイナリデータを扱うプログラムを書く上で、避けて通る事の出来ないバイトオーダーの問題。 | ||
- | 結構頻出な問題だと思うのだが、軽くググってみただけではまとまった解説が見つからなかったので、自分用も兼ねてここにまとめて見る。 | + | それなりに頻出問題だと思うのだが、軽くググってみただけではまとまった解説が見つからなかった。自分用も兼ねてここにまとめて見る。 |
===== バイトオーダーとは何ぞや ===== | ===== バイトオーダーとは何ぞや ===== | ||
- | バイトオーダーとは、多バイトデータをメモリに格納する際のバイトの配置法のことで、エンディアンやエンディアンネスとも呼ばれる。 | + | バイトオーダーとは多バイトデータのメモリへの配置順のことで、エンディアンやエンディアンネスとも呼ばれる。 |
- | バイトオーダーはコンピュータシステムごとに異なり、現在ではx86系などで使用される**リトルエンディアン(LE)**と、PowerPC((ビッグエンディアンなのはG5のみ。G4まではバイエンディアン。))/ | + | バイトオーダーはコンピュータシステムごとに異なり、現在では、x86系などで使用される**リトルエンディアン(LE)**と、PowerPC((ビッグエンディアンなのはG5のみ。G4まではバイエンディアン。))/ |
- | 例えば「0x1234CDEF」という32bit値のメモリ配置は、LE/BEでそれぞれ以下のようになる。 | + | 例えば「0x<fc red> |
- | ^ 番地 | + | ^ 番地 |
- | |0000|EF|12| | + | |0000|<fc orange>EF</fc>|<fc red>12</fc>| |
- | |0001|CD|34| | + | |0001|<fc blue>CD</fc>|<fc green>34</fc>| |
- | |0002|34|CD| | + | |0002|<fc green>34</fc>|<fc blue>CD</fc>| |
- | |0003|12|EF| | + | |0003|<fc red>12</fc>|<fc orange>EF</fc>| |
- | リトルエンディアンはデータの下位バイトから、ビッグエンディアンはデータの上位バイトから、それぞれメモリの下位番地より順次配置される。人間から見ればビッグエンディアンの方が分かりやすいが、コンピュータ的にはリトルエンディアンの方が都合がいいらしい。また、データの下位バイトからメモリの下位番地に格納される、という意味ではリトルエンディアンの方が理にかなっていると考えることもできる。 | + | リトルエンディアンはデータの下位バイト、ビッグエンディアンはデータの上位バイトから、それぞれメモリの下位番地より順次配置される。人間から見ればビッグエンディアンの方が分かりやすいが、コンピュータ的にはリトルエンディアンの方が都合がいいらしい。また、データの下位バイトをメモリの下位番地に配置する、という意味ではリトルエンディアンの方が理にかなっているとも考えられる。 |
===== バイトオーダーの違いによる問題 ===== | ===== バイトオーダーの違いによる問題 ===== | ||
- | ここでリトルエンディアン環境で上表の番地0000~0003の中身をファイルに書き出す、つまりデータの保存を考えてみよう。何も考えずに書き出せば、ファイルの内容は「EFCD3412」となる。 | + | ではここで、データの保存について考えてみる。データの保存とは、とどのつまりメモリの内容をファイルに書き出すことである。 |
+ | |||
+ | 0x1234CDEFの例でいえば、メモリ番地0000~0003をファイルに書き出すことになり、リトルエンディアン環境ではファイルの内容は「EFCD3412」となる。 | ||
次に、そのファイルからメモリの状態を復元、つまりデータの読み込みを考える。 | 次に、そのファイルからメモリの状態を復元、つまりデータの読み込みを考える。 | ||
- | これまた何も考えずにファイル内容をメモリに展開すると、メモリ番地0000から上位番地へ向かって EF CD 34 12 の順で復元される。このメモリ内容は、リトルエンディアン環境ならば**0x1234CDEF**と正しく解釈されるが、ビッグエンディアン環境では**0xEFCD3412**と解釈され保存時とは異なる値になってしまう。 | + | ファイル内容を先頭から順にメモリに展開すると、番地0000から上位番地へ向かって EF CD 34 12 の順で配置される。このメモリ内容は、リトルエンディアン環境ならば**0x1234CDEF**と正しく解釈される一方、ビッグエンディアン環境では**0xEFCD3412**と解釈され元の値とは異なってしまう。 |
このように、データ保存環境のエンディアンとデータ読込環境のエンディアンが異なれば、保存時に意図したデータとは異なるデータになってしまう。これでは宜しくない。 | このように、データ保存環境のエンディアンとデータ読込環境のエンディアンが異なれば、保存時に意図したデータとは異なるデータになってしまう。これでは宜しくない。 | ||
行 45: | 行 47: | ||
という処理を施せばよい。 | という処理を施せばよい。 | ||
- | |||
- | 通常はメモリ上のデータのエンディアンを入れ替える | ||
この処理を行うC言語のマクロは、以下のようになる。一応、1バイト = 8ビットが前提の実装となっているが、それ以外の環境に触れている方はこのページを読まないと思うので気にしない事にする。 | この処理を行うC言語のマクロは、以下のようになる。一応、1バイト = 8ビットが前提の実装となっているが、それ以外の環境に触れている方はこのページを読まないと思うので気にしない事にする。 |