エンディアン

エンディアン(endianness)あるいはバイトオーダ(byte order)は、コンピュータの記憶装置に複数バイト(多バイト)からなる数値を記憶する際の、各バイトの順序についての規則。記憶装置は通信路ともみなせるため、通信で複数バイトを扱う際の、送る順序の規則。

 概要 
コンピュータで扱う数値は、1バイトで表現されるもの以外に、2バイト、4バイト、8バイトなど複数バイト(多バイト)のものもある。記憶装置を汎用化するため、最小の1バイト単位でも扱えるように1バイト毎に番地(アドレス)が連続して割り振られている。記憶装置への多バイト数値配置順序の規則（バイトオーダ、バイト順）も、複数存在する。

 ビッグエンディアンとリトルエンディアン 
数値の1番小さい桁1バイト分を、1番大きいアドレスの記憶装置に配置し順に並べる規則をビッグエンディアンという。それと対称的に、数値の1番小さい桁1バイト分を、1番小さいアドレスの記憶装置に配置し順に並べる規則をリトルエンディアンという。

ビッグエンディアンを採用しているコンピュータやCPUとしては、IBMのメインフレームのz/Architecture（および互換機）、モトローラのMC68000（および後継）、サン・マイクロシステムズのSPARCなどがある。

リトルエンディアンを採用しているものとしては、DECのVAX、インテルのx86、Appleシリコン、などがある。

エンディアンを切り替えられるバイエンディアン (bi-endian) のプロセッサとしては、PowerPCなどがある。なおARMアーキテクチャのコアは両モードをサポートするが、デフォルトの設定としてはリトルエンディアンとしており、ARM向けLinuxディストリビューションの大半はリトルエンディアンのみに対応している。

言語処理系などの仮想マシンの類では、プラットフォームに応じエンディアンを使い分ける設計のものもあれば、片方に寄せる設計のものもある。例えば、Java仮想マシンのクラスファイル内部表現はプラットフォームを問わずビッグエンディアンである。

 ミドルエンディアン 
理論上バイトオーダはビッグエンディアンとリトルエンディアン以外にも存在し、2バイト数値では2!=2*1=2種類、4バイト数値では4!=24種類、8バイト数値では8!=40320種類となる。現在はビッグエンディアンかリトルエンディアンに収束しているが、過去にDECのPDP-11の32ビットワードは、リトルエンディアンの16ビットワードがビッグエンディアンで配置されるという混合的な形式を採用していた。このようなビッグエンディアン・リトルエンディアンを複合した形式はミドルエンディアンとも呼ばれる。

 バイトオーダの実例 
ビッグエンディアン・リトルエンディアン・PDP-11のエンディアンに加えて、理論上は可能な他のバイトオーダの具体例の一部を示すため、4バイトの連続した記憶装置に4バイト数値0x01234567を記憶する例を下で提示する。16進数表記した上記数値の一番小さい桁の1バイト分は0x67であり、一番大きい桁の1バイト分は0x01である。表の相対アドレスは、左が小さいアドレス(オフセット値)+0で、右が大きいアドレス(オフセット値)+3を示すことに注意。

+ 4バイト数値0x01234567の配置相対アドレス(オフセット値)+0+1+2+3ビッグエンディアン01234567リトルエンディアン67452301PDP-1123016745非現実的な規則の一例45672301

 判定プログラムの例 
下記は、記憶装置でのバイトオーダを表示し規則を簡易的に判定するC言語プログラムの例である。表と同じく左が小さいアドレスで、右が大きいアドレスで表示している。

#include <stdint.h>
#include <stdio.h>

int
isLittleEndian(void)
{
    int       i  = 1;
    uint8_t  *p  = (uint8_t *) &i;

    return *p;
}

int
main(int argc, char *argv[])
{
    uint64_t  i8 = 0x0123456789abcdef;
    uint32_t  i4 = 0x01234567;
    uint16_t  i2 = 0x0123;
    double    d  = -1.0/3.0;
    uint8_t  *p;

    /* 8ByteOrder */
    p = (uint8_t *) &i8;
    printf("8Byte Order   %016lx\n", i8);
    printf("   on Memory |%02x|%02x|%02x|%02x|%02x|%02x|%02x|%02x|\n",
           *(p+0), *(p+1), *(p+2), *(p+3),
           *(p+4), *(p+5), *(p+6), *(p+7));

    /* 4ByteOrder */
    p = (uint8_t *) &i4; 
    printf("4Byte Order   %08x\n", i4);
    printf("   on Memory |%02x|%02x|%02x|%02x|\n",
           *(p+0), *(p+1), *(p+2), *(p+3));

    /* 2ByteOrder */
    p = (uint8_t *) &i2; 
    printf("2Byte Order   %04x\n", i2);
    printf("   on Memory |%02x|%02x|\n",
           *(p+0), *(p+1));

    /* 8Byte Double Order */
    p = (uint8_t *) &d;
    printf("DoubleOrder   %lf == %le\n", d, d);
    printf("   on Memory |%02x|%02x|%02x|%02x|%02x|%02x|%02x|%02x|\n",
           *(p+0), *(p+1), *(p+2), *(p+3),
           *(p+4), *(p+5), *(p+6), *(p+7));

    /* UTF8 strings */
    p = (uint8_t *) "01🥺語\n";
    printf("StringOrder   %s", p);
    printf("   on Memory |%02x|%02x|%02x|%02x|%02x|%02x|%02x|%02x|%02x|%02x|%02x|\n",
           *(p+0), *(p+1), *(p+2), *(p+3),
           *(p+4), *(p+5), *(p+6), *(p+7),
           *(p+8), *(p+9), *(p+10));


    if (isLittleEndian()) {
        printf("is LittleEndian\n");
    } else {
        printf("is Not LittleEndian\n");
    }

    return 0;
}

リトルエンディアン、日本語UTF-8のLinux環境での処理結果
 8Byte Order   0123456789abcdef
    on Memory |ef|cd|ab|89|67|45|23|01|
 4Byte Order   01234567
    on Memory |67|45|23|01|
 2Byte Order   0123
    on Memory |23|01|
 DoubleOrder  -0.333333 == -3.333333e-01
    on Memory |55|55|55|55|55|55|d5|bf|
 StringOrder   01🥺語
    on Memory |30|31|f0|9f|a5|ba|e8|aa|9e|0a|00|
 is LittleEndian

 ビットオーダ 
1バイト未満のビット単位の並び順序であるビットオーダ（ビット順）は、レジスタ内順序や信号線の接続順序として電子回路的には存在しているが、プログラマにとっては不要な情報であり、命令セットアーキテクチャなどでは隠蔽されている。シリアル通信をソフトウェア的に実装する場合などはビットの並び順を考える必要があるが、これはCPUの実装には依存しない通信プロトコル上の規定である。

 相互運用 
現在は、ビッグエンディアンおよびリトルエンディアンいづれのコンピュータも存在し、また相互にネットワーク等を介して通信を行うため、コンピュータのネイティブとは異なるエンディアン形式にもOSやソフトウェア等で対応している。TCP/IPの通信規約ではビッグエンディアンが採用され、通信に用いる数値は最上位桁を含む1バイトから先に送受信される。これはネットワークバイトオーダとも呼ばれる。
https://atmarkit.itmedia.co.jp/icd/root/72/116970472.html
https://ascii.jp/elem/000/004/099/4099994/
ハードディスクドライブやテープドライブおよびソリッドステートドライブなども、SASではビッグエンディアン、SATAではリトルエンディアンと、接続規格で定めている。
https://www.seagate.com/staticfiles/support/disc/manuals/sas/100293071b.pdf

画像や音声などのデータフォーマットについては、どちらのエンディアンか規約で決めておいたり、ファイルヘッダ等のメタデータでいづれか指定する方式のものも存在する。
https://xiph.org/flac/format.html
https://www.libpng.org/pub/png/libpng-manual.txt

Unicodeにおいても、構成要素が多バイトとなるエンコーディング（主にUTF-16）では、エンディアンが問題となる。そのため、バイト順マークUnicode Terminology English - Japanese, B, Unicode, Inc.（、略語：BOM）と呼ばれる特殊なコード (U+FEFF) が予約されており、データの先頭にこれを付与することで、データを受け取る側がエンディアンを判別できるようになっている。BOMがない場合には、ビッグエンディアンだと決められている（→ UTF-16）。

ただし、復号側が以上のルールでエンディアンを判別する狭義のUTF-16とは別に、エンディアンを事前に一方に決定しているUTF-16BEとUTF-16LEが存在する。Windows上の文書における「Unicodeテキスト」は、BOMがない場合、UTF-16LE（リトルエンディアン）である。

 日付表現のエンディアン 
エンディアンは、日付の年月日の表現の分類にも使われるDate Format Variations: Little-Endian, Middle-Endian, Big-Endian proofreading academy。2021年4月12日を例に取ると、
 年月日の順（2021/04/12）　ビッグエンディアン Big-Endian　（中国、日本、韓国など）
 日月年の順（12/04/2021）　リトルエンディアン Little-Endian　（英国、フランス、ドイツ、イタリア、ロシアなど）
 月日年の順（04/12/2021）　ミドルエンディアン Middle-Endian　（米国）
日付の国際規格であるISO 8601では、ビッグエンディアンのみが認められている。ただし、区切りの符号は、「/」ではなく、「-」でなければならない（例：2021-04-12）。

 語源 
ビッグエンディアンとリトルエンディアンという語は、18世紀にジョナサン・スウィフトが書いた風刺小説『ガリヴァー旅行記』の中のエピソードに由来する。ガリヴァー旅行記の第1部「小人国」では、ゆで卵を丸い方（大きい方）の端 (big end) から割る人々（）と尖った方（小さい方）の端 (little end) から割る人々 () の党派的な対立が描かれている。

この語を計算機に転用したのはダニー・コーエンで、1980年4月1日に発表したジョークRFC "On Holy Wars and a Plea for Peace"IEN 137 (1 April 1980) http://www.ietf.org/rfc/ien/ien137.txt これ以前の用語が「byte order」であったことなどもわかるD. Cohen. 1981. On Holy Wars and a Plea for Peace. Computer 14, 10 (October 1981), 48-54. （聖戦と平和の嘆願について）で初めて使用した。

 脚注 

 注釈 

 出典 

 関連項目 
 移植性

 外部リンク 
 White Paper: Endianness or Where is Byte 0?

Category:CPU
Category:プログラミング
Category:データ転送
Category:方向
Category:ガリヴァー旅行記
Category:メタファー