この記事には独自研究 が含まれているおそれがあります。 問題箇所を検証 し出典を追加 して、記事の改善にご協力ください。議論はノート を参照してください。(2016年7月 )
エンディアン (endianness)あるいはバイトオーダ (byte order)は、コンピュータ の記憶装置 に複数バイト (多バイト)からなる数値を記憶する際の、各バイトの順序についての規則[ 1] [ 2] 。記憶装置は通信路ともみなせるため、通信 で複数バイトを扱う際の、送る順序の規則[ 3] 。
概要
コンピュータで扱う数値は、1バイトで表現されるもの以外に、2バイト、4バイト、8バイトなど複数バイト(多バイト)のものもある。記憶装置を汎用化するため、最小の1バイト単位でも扱えるように1バイト毎に番地(アドレス)が連続して割り振られている。記憶装置への多バイト数値配置順序の規則(バイトオーダ、バイト順)も、複数存在する。
ビッグエンディアンとリトルエンディアン
リトルエンディアン(左)とビッグエンディアン(右)
数値の1番小さい桁1バイト分を、1番大きいアドレスの記憶装置に配置し順に並べる規則をビッグエンディアン という。それと対称的に、数値の1番小さい桁1バイト分を、1番小さいアドレスの記憶装置に配置し順に並べる規則をリトルエンディアン という。[ 1] [ 2]
ビッグエンディアンを採用しているコンピュータやCPUとしては、IBM のメインフレーム (および互換機)、モトローラ のMC68000 (および後継)、サン・マイクロシステムズ のSPARC などがある。
リトルエンディアンを採用しているものとしては、DEC のVAX 、インテル のx86 、Appleシリコン 、などがある。
エンディアンを切り替えられるバイエンディアン (bi-endian) のプロセッサとしては、PowerPC などがある。なおARMアーキテクチャ のコアは両モードをサポートするが、デフォルトの設定としてはリトルエンディアンとしており、ARM向けLinuxディストリビューション の大半はリトルエンディアンのみに対応している[ 4] 。
言語処理系などの仮想マシンの類では、プラットフォームに応じエンディアンを使い分ける設計のものもあれば、片方に寄せる設計のものもある。例えば、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の配置[ 1] [ 2]
相対アドレス(オフセット値)
+0
+1
+2
+3
ビッグエンディアン
01
23
45
67
リトルエンディアン
67
45
23
01
PDP-11
23
01
67
45
非現実的な規則の一例
45
67
23
01
判定プログラムの例
下記は、記憶装置でのバイトオーダを表示し規則を簡易的に判定する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 環境での処理結果
8 Byte Order 01234567 89 abcdef
on Memory | ef | cd | ab | 89 | 67 | 45 | 23 | 01 |
4 Byte Order 01234567
on Memory | 67 | 45 | 23 | 01 |
2 Byte 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 | 9 e | 0 a | 00 |
is LittleEndian
ビットオーダ
1バイト未満のビット単位の並び順序であるビットオーダ(ビット順)は、レジスタ内順序や信号線の接続順序として電子回路的には存在しているが、プログラマにとっては不要な情報であり、命令セットアーキテクチャなどでは隠蔽されている。シリアル通信をソフトウェア的に実装する場合などはビットの並び順を考える必要があるが、これはCPUの実装には依存しない通信プロトコル上の規定である。
相互運用
現在は、ビッグエンディアンおよびリトルエンディアンいづれのコンピュータも存在し、また相互にネットワーク等を介して通信を行うため、コンピュータのネイティブとは異なるエンディアン形式にもOSやソフトウェア等で対応している。TCP/IP の通信規約ではビッグエンディアンが採用され、通信に用いる数値は最上位桁を含む1バイトから先に送受信される。これはネットワークバイトオーダ とも呼ばれる。
[ 5]
[ 6]
ハードディスクドライブ やテープドライブ およびソリッドステートドライブ なども、SASではビッグエンディアン、SATAではリトルエンディアンと、接続規格で定めている。
[ 7]
画像や音声などのデータフォーマットについては、どちらのエンディアンか規約で決めておいたり、ファイルヘッダ等のメタデータでいづれか指定する方式のものも存在する。
[ 8]
[ 9]
Unicode においても、構成要素が多バイトとなるエンコーディング(主にUTF-16)では、エンディアンが問題となる。そのため、バイト順マーク [ 10] (英 : Byte Order Mark 、略語:BOM)と呼ばれる特殊なコード (U+FEFF) が予約されており、データの先頭にこれを付与することで、データを受け取る側がエンディアンを判別できるようになっている。BOMがない場合には、ビッグエンディアンだと決められている(→ UTF-16 )。
ただし、復号側が以上のルールでエンディアンを判別する狭義のUTF-16とは別に、エンディアンを事前に一方に決定しているUTF-16BEとUTF-16LEが存在する。Windows 上の文書における「Unicodeテキスト」は、BOMがない場合、UTF-16LE(リトルエンディアン)である。
日付表現のエンディアン
エンディアンは、日付の年月日の表現 の分類にも使われる[ 11] 。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) から割る人々(英 : Big-Endians )と尖った方(小さい方)の端 (little end) から割る人々 (英 : Little-Endians ) の党派的な対立が描かれている。
この語を計算機に転用したのはダニー・コーエン で、1980年4月1日に発表したジョークRFC "On Holy Wars and a Plea for Peace"[ 12] [ 13] (聖戦と平和の嘆願について)で初めて使用した。
脚注
注釈
出典
関連項目
外部リンク