エンディアン
エンディアン(endianness)あるいはバイトオーダ(byte order)は、コンピュータの記憶装置に複数バイトからなる数値を配置する規則。 [1] [2]
記憶装置は通信路ともみなせるため、通信で複数バイトを扱う際に、送る順序の規則でもある。 [3]
概要[編集]
コンピュータで扱う数値は、1バイトや2バイト、4バイトや8バイトなど複数の処理単位がある。 そのため記憶装置を汎用化し最小の1バイト単位でも扱えるように、1バイト毎に番地(アドレス)が連続して割り振られている。
複数バイトの数値を複数アドレスの記憶装置に配置する規則であるバイトオーダも複数ある。 特に、 数値の1番小さい桁1バイト分を、1番大きいアドレスの記憶装置に配置し順に並べる規則はビッグエンディアンと呼ぶ。 対称的に、 数値の1番小さい桁1バイト分を、1番小さいアドレスの記憶装置に配置し順に並べる規則をリトルエンディアンと呼ぶ。 [1][2]
バイトオーダの種類は、2バイト数値では2!=2*1=2種類、4バイト数値では4!種類、8バイト数値では8!種類もあるが、不規則な並びを採用する必然性が無く、いずれもリトルエンディアンかビッグエンディアンの2種類に収束している。
1バイト未満のビット単位の並び順序であるビットオーダは、レジスタ内順序や信号線の接続順序として存在するが、命令セットやユーザープログラムの観点からは不要で隠蔽されている。
バイトオーダの実例[編集]
4バイトの数値0x01234567を記憶するために、4バイトの連続した記憶装置に並べる例を提示する。 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 |
下記は、記憶装置でのバイトオーダを表示し、規則を簡易的に判定する例である。 表と同じく左が小さいアドレスで、右が大きいアドレスで表示している。
#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
IBMのメインフレーム︵および互換機︶、モトローラのMC68000︵および後継︶、サン・マイクロシステムズのSPARCなどはビッグエンディアンを採用し、DECのVAX、インテルのx86などはリトルエンディアンを採用している。ARMアーキテクチャ、PowerPCなど、エンディアンを切り替えられるバイエンディアン (bi-endian) のプロセッサも存在する。 言語処理系などの仮想マシンの類では、プラットフォームに応じ使い分ける設計のものもあれば、片方に寄せる設計のものもある。例えば、Java仮想マシンはプラットフォームを問わずビッグエンディアンである。