エンディアン
![]() |
![]() | この記事には独自研究が含まれているおそれがあります。 |
エンディアン(英: endianness)あるいはバイトオーダ(byte order)は、コンピュータの記憶装置に複数バイト(多バイト)からなる数値を記憶する際の、各バイトの順序についての規則[1][2]。また、通信で複数バイトを扱う際の、送る順序についての規則[3]。
概要
[編集]コンピュータで扱う数値(やデータ)は、1バイトで表現されるもの以外に、2バイト、4バイト、8バイトなど複数バイト(多バイト)で表現されるものがある。一方、記憶装置は汎用化され、最小の1バイト単位でも扱えるように、1バイト毎に番地(アドレス)が連続して割り振られている。すると、多バイトの数値やデータの各バイトをどのような順序で記憶装置に格納するかについての規則(バイトオーダ、バイト順)は、いくつか種類(選択肢)があることになる。
ビッグエンディアンとリトルエンディアン
[編集]![](http://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/32bit-Endianess.svg/langja-400px-32bit-Endianess.svg.png)
数値の1番小さい桁1バイト分を、1番大きいアドレスの記憶装置に配置し順に並べる規則をビッグエンディアンという。それと対称的に、数値の1番小さい桁1バイト分を、1番小さいアドレスの記憶装置に配置し順に並べる規則をリトルエンディアンという[1][2]。
ビッグエンディアンを採用しているコンピュータやCPUとしては、IBMのメインフレーム(および互換機)、モトローラのMC68000(および後継)、サン・マイクロシステムズのSPARCなどがある。
リトルエンディアンを採用しているものとしては、DECのVAX、インテルのx86、Appleシリコン、などがある。
エンディアンを切り替えられるバイエンディアン (bi-endian) のプロセッサとしては、PowerPCなどがある。なおARMアーキテクチャのコアは両モードをサポートするが、デフォルトの設定としてはリトルエンディアンとしており、ARM向けLinuxディストリビューションの大半はリトルエンディアンのみに対応している[4]。
言語処理系などの仮想マシンの類では、プラットフォームに応じエンディアンを使い分ける設計のものもあれば、片方に寄せる設計のものもある。例えば、Java仮想マシンはプラットフォームを問わずビッグエンディアンである。
ミドルエンディアン
[編集]理論的に言えば、バイトオーダの種類はビッグエンディアン・リトルエンディアン以外にも多数考えられる[注釈 1]。現実には単純で使いやすいビッグエンディアンかリトルエンディアンがほとんどのプロセッサで使われているが、例外も存在し、DECのPDP-11の32ビットワードは、リトルエンディアンの16ビットワードがビッグエンディアンで配置されるという混合的な形式を採用していた。このようなビッグエンディアン・リトルエンディアンを複合した形式はミドルエンディアンと呼ばれる。
バイトオーダの実例
[編集]ビッグエンディアン・リトルエンディアン・PDP-11のエンディアンに加えて、理論上は可能な他のバイトオーダの具体例の一部を示すため、4バイトの連続した記憶装置に4バイト数値0x01234567を記憶する例を下で提示する。16進数表記した上記数値の一番小さい桁の1バイト分は0x67であり、一番大きい桁の1バイト分は0x01である。表のアドレスは、左が小さいアドレス80で、右が大きいアドレス83を示すことに注意。
アドレス | 80 | 81 | 82 | 83 |
---|---|---|---|---|
ビッグエンディアン | 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, *(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, *(p+1), *(p+2), *(p+3));
/* 2ByteOrder */
p = (uint8_t *) &i2;
printf("2Byte Order %04x\n", i2);
printf(" on Memory |%02x|%02x|\n",
*p, *(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, *(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, *(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の実装には依存しない通信プロトコル上の規定である。
互換性・移植性
[編集]エンディアンの相違は、単一あるいは同種のシステムに閉じた運用をする限りでは通常は問題にならない。一方、次のような場合ではエンディアンの相違が問題となり正常な動作をしないことがある。
- ネットワークを通してバイト単位でデータをやりとりする場合
- 異なるシステム間でバイナリファイルなどを交換する場合
- 異なるシステムにプログラムを移植する場合
- 構成するプロセッサが異なるマルチプロセッサ環境で共有メモリを使用する場合
TCP/IPプロトコルスタックでは、ビッグエンディアンに統一しており、それをネットワークバイトオーダという。この分野では、それに対し、各コンピュータのエンディアンをホストバイトオーダという。
画像や音声などのバイナリファイルにおいても、異なるコンピュータ間の互換性を確保するため、通常はエンディアンが規定される。
Unicodeにおいても、構成要素が多バイトとなるエンコーディング(主にUTF-16)では、エンディアンが問題となる。そのため、バイト順マーク[5](英: Byte Order Mark、略語:BOM)と呼ばれる特殊なコード (U+FEFF) が予約されており、データの先頭にこれを付与することで、データを受け取る側がエンディアンを判別できるようになっている。BOMがない場合には、ビッグエンディアンだと決められている(→ UTF-16)。
ただし、復号側が以上のルールでエンディアンを判別する狭義のUTF-16とは別に、エンディアンを事前に一方に決定しているUTF-16BEとUTF-16LEが存在する。Windows上の文書における「Unicodeテキスト」は、BOMがない場合、UTF-16LE(リトルエンディアン)である。
日付表現のエンディアン
[編集]エンディアンは、日付の年月日の表現の分類にも使われる[6]。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"[7][8](聖戦と平和の嘆願について)で初めて使用した。
脚注
[編集]注釈
[編集]- ^ 数学的に可能な組み合わせは2バイト数値では2!=2*1=2種類、4バイト数値では4!=24種類、8バイト数値では8!=40320種類となる。
出典
[編集]- ^ a b c ブライアン・カーニハン、ロブ・パイク『プログラミング作法』アスキー出版。ISBN 4-7561-3649-4。
- ^ a b c 中森章『マイクロプロセッサ・アーキテクチャ入門 インターフェース増刊 TECHI Vol.20』CQ出版。
- ^ 村松純、岩田賢一、有村光晴、渋谷智治『情報理論』オーム社。ISBN 978-4-274-20595-8。
- ^ “Endianness” (英語). ARM Cortex-R Series Programmer's Guide. Arm Limited (or its affiliates). 2024年7月17日閲覧。
- ^ Unicode Terminology English - Japanese, B, Unicode, Inc.
- ^ Date Format Variations: Little-Endian, Middle-Endian, Big-Endian proofreading academy
- ^ 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. doi:10.1109/C-M.1981.220208