エンディアン
エンディアン (英: endianness) とは、多バイトのデータ(即ち基本情報記憶単位を超えるデータ)をメモリ上に配置する方式の種類のこと。エンディアンネス 、バイト順、バイトオーダ (英: byte order) ともいう。
日本では「エンディアン」という呼称が広く使われているが、英語の「endian」という単語自体には「配置方式」「並び順」といった意味はない。(#語源)
目次 |
[編集] 概要
例えば 1234ABCD(16進数)という4バイトのデータを、データの上位バイトからメモリに「12 34 AB CD」と並べる方式をビッグエンディアン[1]、データの下位バイトから「CD AB 34 12」と並べる方式をリトルエンディアン[2]という。その他に「34 12 CD AB」あるいは「AB CD 12 34」のように並べる方式もあり、ミドルエンディアン[3]、あるいはDECのPDP-11で使われていたことからPDPエンディアンなどと呼ばれるが、現在ではほとんど見られない。
ビッグエンディアンは人間にとって直観的にわかりやすいという利点があり、一方リトルエンディアンはコンピュータにとって処理しやすい(多倍長加算の起点は最下位バイトであることなど)という利点がある。
IBM系のメインフレーム/汎用機、サン・マイクロシステムズのSPARC、MotorolaのMC68000等は「ビッグエンディアン」を採用し、インテルのx86系などは「リトルエンディアン」を採用している。ARMアーキテクチャのCPU、トランスメタ社のCrusoe、Hewlett-Packard社のPA-RISC、PowerPCなど、エンディアンを切り替えられるバイエンディアン (bi-endian) のものも存在する。ただし稼動CPUを問わずJava仮想マシンについてはビッグエンディアンである。
[編集] 互換性・移植性
エンディアンの相違は、単一あるいは同種のシステムに閉じた運用をする限りでは通常は問題にならないが、以下のような場合に問題になることがある。
- ネットワークを通してバイト単位でデータをやりとりする場合
- 異なるシステム間でバイナリファイル等を交換する場合
- 異なるシステムにプログラムを移植する場合
- 構成するプロセッサが異なるマルチプロセッサ環境で共有メモリを使用する場合
TCP/IPネットワークでは、エンディアンの異なるコンピュータ間での通信を可能とするため、パケットなどに含まれる多バイトデータはビッグエンディアンに統一することと決められている。これをネットワークバイトオーダという。これに対し、それぞれのコンピュータ上でのエンディアンのことをホストバイトオーダという。
画像や音声などのバイナリファイルにおいても、互換性を確保するため、エンディアンが規定されている例が多い。
Unicodeにおいても、構成要素が多バイトとなるエンコーディング(主にUTF-16)では、エンディアンが問題となる。そのため、バイト順マーク[4](英: Byte Order Mark、略語:BOM)と呼ばれる特殊なコード (U+FEFF) が予約されており、データの先頭にこれを付与することで、データを受け取る側がエンディアンを判別できるようになっている。BOMがない場合には、ビッグエンディアンだと決められている(→ UTF-16)。
ただし、復号側が以上のルールでエンディアンを判別する狭義のUTF-16とは別に、エンディアンを事前に一方に決定しているUTF-16BEとUTF-16LEが存在する。Windows上の文書における「Unicodeテキスト」は、BOMがない場合、UTF-16LE(リトルエンディアン)である。
[編集] 例
より詳しく説明するため、この章では最も一般的な32ビット機のエンディアンの例を示す。
すべての例は 0A0B0C0D という値をメモリに格納した場合を示している。
[編集] ビッグエンディアン
- 8bitで1ずつアドレスが増加する場合
| アドレス増加 → | |||||
| 0A | 0B | 0C | 0D | ||
例では最上位バイト (MSB) は0Aとなり、メモリ上では一番低いアドレスに保存され、次のバイト 0Bは続いて格納される。これは16進で左から右に読むのに似ている。
- 16bitで1ずつアドレス増加する場合
| アドレス増加 → | |||||
| 0A0B | 0C0D | ||||
最上位に0A0Bが保存され、続いて0C0Dが保存される。
[編集] リトルエンディアン
- 8bitで1ずつアドレスが増加する場合
| アドレス増加 → | |||||
| 0D | 0C | 0B | 0A | ||
最下位バイト(LSB)は0Dで、そのアドレスは一番低い。他のバイトはアドレス増加に追従する。
- 16bitで1ずつアドレス増加する場合
| アドレス増加 → | |||||
| 0C0D | 0A0B | ||||
16ビットで格納されている最下位の値は0C0Dで続いて0A0Bが入る。
- バイトアドレスが右から左に増加する場合:
16ビットで格納されている場合、上述しているように逆からになるが、リトルエンディアンの場合、左に向かって書くと良いからである。もしこの方法で記載した場合、ちょっとしたセンスが必要で、
| ← アドレス増加 | |||||
| 0A | 0B | 0C | 0D | ||
となる。 最下位バイト(LSB)は0Dとなり、一番低いアドレスとなる。他のバイトはアドレス増加に追従する。
| ← アドレス増加 | |||||
| 0A0B | 0C0D | ||||
最下位の16ビットは0C0Dとなり次に0A0Bとなる。 しかしながらもしこのようにメモリが左に増加するように表示するとUnicode又はASCIIテキストを表示すると普通に表示する場合の逆(左から右)となる。たとえば「BYTE」をリトルエンディアン用記法で表現すると
| ← アドレス増加 | |||||
| 「E」 | 「T」 | 「Y」 | 「B」 | ||
このメモリ配列とバイナリデータとの衝突はリトルエンディアンに基本的に備わっているものであるが、この衝突は左から右に書かれる言語[5]でだけで起きる。右から左に書く言語[6]はバイナリでも衝突はおきず、手際よくアドレスを左に向けて増加できる。(逆に、右から左に書く言語はビッグエンディアンシステムで衝突が起きる)
[編集] ミドルエンディアン
さらに他のアーキテクチャでは、ミドルエンディアン又はミックスドエンディアンと一般的には呼ばれるさらに込み入ったバイトオーダもある。
例えばPDP-11であれば、最上位バイトから「0B」「0A」「0D」「0C」の順に格納される。つまり、最上位ハーフ(16ビット)と次のハーフ(16ビット)がビッグエンディアンで格納され、各ハーフ(16ビット)内の各バイトはリトルエンディアンとして格納される。これはPDP-エンディアンと知られている。
- PDP-11に32ビットワードを格納する場合
| アドレス増加 → | |||||
| 0B | 0A | 0D | 0C | ||
ARMアーキテクチャは32ビットワードを32ビットワードから2バイトに格納した場合、このエンディアンを生成することができる。
[編集] エンディアンの確認
[編集] od コマンド
UNIX や Linux においては多くの環境にインストールされているodコマンドがエンディアン依存の実行結果を表示するため、odコマンドで実行環境のエンディアンを確認することができる。
$ echo -n "12345" | od -t x
32bit機ビッグエンディアンでの出力結果
0000000 31323334 35000000 0000005
32bit機リトルエンディアンでの出力結果
0000000 34333231 00000035 0000005
[編集] C言語
C言語又では共用体、ポインタ等を使ってエンディアンを確かめることが出来る。逆に言えば使用環境に依存するプログラムになってしまうとも言える。以下に環境依存のプログラムを示す。[7]
#include <stdio.h> int main (int argc, char **argv) { union { int b4 ; /* 4byte */ unsigned short b2 [2] ; /* 2byte×2 */ unsigned char b4 [4] ; /* 1byte×4 */ } bytes ; bytes.b4 = 0x12345678 ; printf ("bytes.b4: %08X\n", bytes.b4) ; printf ("bytes.b2: %04X, %04X\n", bytes.b2[0], bytes.b2[1]) ; printf ("bytes.b1: %02X, %02X, %02X, %02X\n", bytes.b1[0], bytes.b1[1], bytes.b1[2], bytes.b1[3]) ; return 0 ; }
32ビット機ビッグエンディアンでの出力結果
bytes.b4: 12345678 bytes.b2: 1234, 5678 bytes.b1 is 12, 34, 56, 78
32ビット機リトルエンディアンでの出力結果
bytes.b4: 12345678 bytes.b2: 5678, 1234 bytes.b1: 78, 56, 34, 12
となる。
[編集] 語源
ビッグエンディアンとリトルエンディアンという単語は、ジョナサン・スウィフトの風刺小説『ガリヴァー旅行記』の中のエピソードに由来する[8]。ガリバー旅行記の第1部「小人国」では、卵を丸い方(大きい方)の端から割る人々 (英: Big Endians) と尖った方(小さい方)の端から割る人々 (Little Endians) との対立が描かれている。
[編集] 脚注
- ^ 英: big endian
- ^ little endian
- ^ 英: middle endian
- ^ Unicode Terminology English - Japanese, B, Unicode, Inc.
- ^ 例えばインドヨーロッパ語族の英語(ラテン文字)、フランス語(ラテン文字)、ロシア語(キリル文字)やヒンディー語(デーバナーガリー文字)。
- ^ アラビア語、ヘブライ語
- ^ ただしC89準拠。またC99完全準拠ではないが Visual Studio 2008 C++ Express Edition、GCC3.4.5-20060117-3 で動作確認済み。また共用体の要素
b2とb4が符号なし(unsigned)になっているのは、printf関数の仮引数に値を受け渡すコードを処理系が生成する際に、最上位ビットの値に関係なく正の数として扱うコードにするよう処理系に指示するためのものである。 - ^ 奥村晴彦 『C言語による最新アルゴリズム事典』 技術評論社、1991年、16頁。ISBN 4-87408-414-1。