本記事では、エンディアンについて解説します。エンディアンはネットワーク通信やバイナリデータを処理するときに重要な概念です。
まず、エンディアンを理解する上で必要となるメモリとバイトについて説明します。
メモリ
メモリは、実行中のプログラムやデータを一時的に格納する部品です。
メモリは読み書き可能なメモリセルで構成されています。それぞれのメモリセルは、電圧の高低で 0 または 1 (1 ビットの情報)を記憶します。
1 バイト( = 8 ビット)ずつにアドレス(番地)と呼ばれる番号がついています。1 つのアドレスごとに 28(= 256)通りの情報を表現できます。
CPU はこのアドレスを指定して、メモリに格納された命令やデータを読み出したり、データを書き込んだりします。
バイト
メモリの説明のなかでも紹介しましたが、バイトは情報量を表す単位です。
1 バイト(= 8 ビット)のメモリやストレージは、256 ( = 28)通りの異なる値(01000001
や 00110000
など)を表現できます。
1 バイトでは表現できる情報が限られているため、数値や画像、音声などのより大きなデータを扱うには、2 バイト以上のメモリやストレージが必要になります。
010010011001011011010010
のような 2 バイト以上のデータの上 8 桁(01001001
)は最上位バイト、下 8 桁(11010010
)は最下位バイトと呼びます。
2 バイト以上のデータを、メモリやデータ転送で扱う際にエンディアンという概念が重要になります。
エンディアンとは
エンディアンとは、データの格納順序や取り出し方を決めるルールです。バイトオーダーとも呼ばれます。2 バイト以上のデータをメモリ上に格納したり、ネットワークを通じて送信したりする際に重要になります。
エンディアンには主に 2 つの方式があります。
ビッグエンディアンとリトルエンディアンです。
メモリ上で 2 バイト以上のデータは、ビッグエンディアンでは、最上位バイトから順に最小のメモリアドレスに格納されます。対照的に、リトルエンディアンでは、最下位バイトから順に格納されます。
32 ビットの数値 01001001100101100000001011010010
(10 進数で 123456789
)は最上位バイトが 01001001
で、最下位バイトが 11010010
です。
どちらのエンディアンを使っているかによって、同じデータでもメモリに格納される順番が異なります。
ビッグエンディアンで格納されたデータをリトルエンディアンとして解釈するなど、誤ったエンディアンで解釈すると全く異なる値になってしまい、データ処理で重大なエラーを引き起こす可能性があります。
例えば、32 ビットの数値 01001001100101100000001011010010
(10 進数で 123456789
)をビッグエンディアンとしてメモリに格納した後、(格納した順序と逆順に)リトルエンディアンとして解釈すると、11010010000000101001011001001001
(10 進数で 3523384905
)となってします。
エンディアンは、特にメモリ、ネットワーク通信、ファイルフォーマットにおいて重要な影響を及ぼします。
-
CPU のエンディアン
CPU の設計によってエンディアンが決定されます。x86 や ARM1 などの多くのパソコン用 CPU はリトルエンディアンです。 -
ファイルフォーマット
PNG や WAV などのファイルフォーマットは、それぞれの仕様に従ったエンディアンを使用しています。PNG はビッグエンディアン、WAV はリトルエンディアンです。
ファイルを読み書きする際には、そのフォーマットに従ったエンディアンでデータを処理する必要があります。 -
ネットワークプロトコル
多くのネットワークプロトコルのヘッダーはビッグエンディアンを使用しています。そのため、リトルエンディアンの CPU では変換が必要になることがあります。
おわりに
バイナリデータを扱う際には、エンディアンに注意することが必要です。エンディアンの違いによって、同じデータが異なる順序で格納され、誤った解釈が行われるとデータの整合性が失われる可能性があります。
-
ARM はデフォルトではリトルエンディアンを使用しますが、ビッグエンディアンとリトルエンディアンの両方をサポートするバイエンディアンです。設定でエンディアンを切り替えることができます。 ↩