「エンディアン」の版間の差分
m →語源 |
|||
123行目: | 123行目: | ||
C言語では共用体を使ってエンディアンを確かめることが出来る。ただし、標準規格では処理系定義とされている動作に依存している<ref>標準規格では、共用体を使って、同じ領域を異なる型としてアクセスした場合は処理系定義である。ポインタを使ってアクセスするのは、strict aliasing ruleにより未定義であるので良くない。ここで示しているコードは、インテルCPUのシステムでVisual C++ 2013、GCC 4.9.3で動作確認済み。</ref>。 |
C言語では共用体を使ってエンディアンを確かめることが出来る。ただし、標準規格では処理系定義とされている動作に依存している<ref>標準規格では、共用体を使って、同じ領域を異なる型としてアクセスした場合は処理系定義である。ポインタを使ってアクセスするのは、strict aliasing ruleにより未定義であるので良くない。ここで示しているコードは、インテルCPUのシステムでVisual C++ 2013、GCC 4.9.3で動作確認済み。</ref>。 |
||
< |
<syntaxhighlight lang="c"> |
||
#include <stdint.h> |
#include <stdint.h> |
||
#include <stdio.h> |
#include <stdio.h> |
||
142行目: | 142行目: | ||
return 0 ; |
return 0 ; |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
32ビット機ビッグエンディアンでの出力結果 |
32ビット機ビッグエンディアンでの出力結果 |
||
bytes.b4: 12345678 |
bytes.b4: 12345678 |
||
155行目: | 155行目: | ||
64bit版だと<ref>intel Corei5プロセッサ、Clang(clang-1000.11.45.5, docker gcc 6.3.0 20170516で確認。記録は「Endian確認プログラム、64bitを追加。」https://qiita.com/kaizen_nagoya/items/f55112ca74936fd30fcb</ref> |
64bit版だと<ref>intel Corei5プロセッサ、Clang(clang-1000.11.45.5, docker gcc 6.3.0 20170516で確認。記録は「Endian確認プログラム、64bitを追加。」https://qiita.com/kaizen_nagoya/items/f55112ca74936fd30fcb</ref> |
||
< |
<syntaxhighlight lang="c"> |
||
#include <inttypes.h> |
#include <inttypes.h> |
||
#include <stdint.h> |
#include <stdint.h> |
||
177行目: | 177行目: | ||
return 0 ; |
return 0 ; |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
== 語源 == |
== 語源 == |
2020年7月5日 (日) 22:39時点における版
この記事には独自研究が含まれているおそれがあります。 |
エンディアン(英: endianness)は、複数のバイトなどを並べる順序の種類である。一般的な用語による表現ではバイトオーダ(英: byte order)、ないしそれを一部訳して日本語ではバイト順とも言う。
英語の「endian」という単語自体には元々は「配置方式」「並び順」といった意味はなかった(#語源を参照)。日本では総称として「エンディアン」と呼ぶことが多いが、英語でそれに相当する語は英: endianness(エンディアンネス)である。
概要
例えば、十六進法で表現すると 1234ABCD という1ワードが4バイトのデータを、バイト毎に上位側から「12 34 AB CD」のように並べる順序はビッグエンディアン[1]、下位側から「CD AB 34 12」のように並べる順序はリトルエンディアン[2]である。その他に「34 12 CD AB」あるいは「AB CD 12 34」のように並べる方式もあり、ミドルエンディアン[3]などという。またこのミドルエンディアンの2つのうちの前者は、DECのPDP-11で使われていたことからPDPエンディアンなどとも呼ばれる。ミドルエンディアンは、後付けの拡張などが理由で現れるが、実例はそんなに多くはない。
一般にエンディアンと言えばバイト(オクテット)のそれを指していることが多いが、任意の長さのワードに対して考えることもでき、ビットに対しても言える(ただし、ビットに関しては、「ビッグ」「リトル」の順序に混乱がある場合があるようであり、MSB first / LSB first のような表現を使ったほうが安全ではある)。
ビッグエンディアンは、メモリ内にそのように並べた場合に、一般的なバイト単位で出力するダンプリストや、メモリ内の通常の文字列の場合と同様にして出力すると、人間が普段慣れている記法と同じ順序になるのでわかりやすいという利点がある。
一方、リトルエンディアンは例えば、バイト毎の並びを、256進法であるとして見た場合に、アドレス+0 にあるのが 2560 の桁、アドレス+1 にあるのが 2561 の桁といったように、数値の表現法と対応しているという整合性がある。また、データの送受信などにおける順番では、多倍長加算などで最下位から順番に計算したほうが繰上りの計算がしやすいこと、などとも相性がよい。なおネットワーク機器などで、アドレスの上位で送り先のおおまかな識別ができる場合など、キャリアグレードルータ等ではデータを受信しながら処理を始めてしまうといったものもあり、そういった場合はビッグエンディアンに利がある。
IBMのメインフレーム(及び互換機)、モトローラのMC68000(及び後継)、サン・マイクロシステムズのSPARC等はビッグエンディアンを採用し、DECのVAX、インテルのx86等はリトルエンディアンを採用している。ARMアーキテクチャ、PowerPCなど、エンディアンを切り替えられるバイエンディアン (bi-endian) のプロセッサも存在する。
言語処理系などの仮想マシンの類では、プラットフォームに応じ使い分ける設計のものもあれば、片方に寄せる設計のものもある。例えば、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 という値をメモリに格納した場合を示している。
ビッグエンディアン
- 8ビットで1ずつアドレスが増加する場合
アドレス増加 → | |||||
0A | 0B | 0C | 0D |
例では最上位バイト (MSB) は 0A となり、メモリ上では一番低いアドレスに保存され、次のバイト 0B は続いて格納される。これは16進で左から右に読むのに似ている。
- 16ビットで1ずつアドレス増加する場合
アドレス増加 → | |||||
0A0B | 0C0D |
最上位に 0A0B が保存され、続いて 0C0D が保存される。
リトルエンディアン
- 8ビットで1ずつアドレスが増加する場合
アドレス増加 → | |||||
0D | 0C | 0B | 0A |
最下位バイト (LSB) は 0D で、そのアドレスは一番低い。他のバイトはアドレス増加に追従する。
- 16ビットで1ずつアドレス増加する場合
アドレス増加 → | |||||
0C0D | 0A0B |
16ビットで格納されている最下位の値は 0C0D で続いて 0A0B が入る。
ミドルエンディアン
さらに、ミドルエンディアン又はミックスドエンディアンと総称的に呼ばれることもある、さらに込み入ったバイトオーダもある(こういった「変」なものを扱う時は、どのような組合せなのか具体例での注意深い確認が欠かせない)。
著名な例としては、PDP-11における32ビットワードの扱い方がある。PDP-11では 0x0A0B0C0D が、最上位バイトから 0B 0A 0D 0C という順に格納される。つまり、上位ハーフワード(16ビット)と下位ハーフワードとしてはビッグエンディアンで格納される。各ハーフワード内の上位下位の各オクテットはリトルエンディアンで格納される。PDP-エンディアンという別名がある。
- PDP-11に32ビットワードを格納する場合
アドレス増加 → | |||||
0B | 0A | 0D | 0C |
ARMアーキテクチャは32ビットワードを32ビットワードから2バイトに格納した場合、このエンディアンを生成することができる。 バグが由来であるとする根拠はない [要出典]。[5]MIPSのELFファイル中に、64ビットワードを「上位32ビットはビッグエンディアン、下位32ビットはリトルエンディアン」で格納する、というフィールドがある[6]。[信頼性要検証]
エンディアンの確認
C言語
C言語では共用体を使ってエンディアンを確かめることが出来る。ただし、標準規格では処理系定義とされている動作に依存している[7]。
#include <stdint.h>
#include <stdio.h>
int main (int argc, char **argv)
{
union
{
uint32_t b4 ; /* 4byte */
uint16_t b2 [2] ; /* 2byte×2 */
uint8_t b1 [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: 12, 34, 56, 78
32ビット機リトルエンディアンでの出力結果
bytes.b4: 12345678 bytes.b2: 5678, 1234 bytes.b1: 78, 56, 34, 12
となる。
64bit版だと[8]
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
int main (int argc, char **argv)
{
union
{
uint64_t b8 ; // 8byte
uint32_t b4 [2] ; // 4byte x 2
uint16_t b2 [4] ; // 2byte × 4
uint8_t b1 [8] ; // 1byte × 8
} bytes ;
bytes.b8 = 0x123456789ABCDEF0 ;
printf ("bytes.b8: %16" PRIX64 "\n", bytes.b8);
printf ("bytes.b4: %08" PRIX32 ", %08" PRIX32 " \n", bytes.b4[0], bytes.b4[1]) ;
printf ("bytes.b2: %04" PRIX16 ", %04" PRIX16 ", %04" PRIX16 ", %04" PRIX16 " \n", bytes.b2[0], bytes.b2[1], bytes.b2[2], bytes.b2[3]) ;
printf ("bytes.b1: %02" PRIX8 ", %02" PRIX8 ", %02" PRIX8 ", %02" PRIX8 ", %02" PRIX8 ", %02" PRIX8 ", %02" PRIX8 ", %02" PRIX8 " \n", bytes.b1[0], bytes.b1[1], bytes.b1[2], bytes.b1[3], bytes.b1[4], bytes.b1[5], bytes.b1[6], bytes.b1[7]) ;
return 0 ;
}
語源
ビッグエンディアンとリトルエンディアンという語は、ジョナサン・スウィフトの風刺小説『ガリヴァー旅行記』の中のエピソードに由来する。ガリバー旅行記の第1部「小人国」では、ゆで卵を丸い方(大きい方)の端 (big end) から割る人々(英: Big Endians)と尖った方(小さい方)の端 (little end) から割る人々 (Little Endians) との対立が描かれている。
この語を計算機に転用したのはダニー・コーエンで、1980年4月1日に発表したジョークRFC"On Holy Wars and a Plea for Peace"[9][10](聖戦と平和の嘆願について)で初めて使用した。
脚注
- ^ 英: big endian
- ^ 英: little endian
- ^ 英: middle endian
- ^ Unicode Terminology English - Japanese, B, Unicode, Inc.
- ^ en:Bug compatibility のせいでそのまま定着してしまったという記録もない [要出典]。
- ^ https://gist.github.com/rui314/b3a5b107ce20c2d54f345216cc15a980
- ^ 標準規格では、共用体を使って、同じ領域を異なる型としてアクセスした場合は処理系定義である。ポインタを使ってアクセスするのは、strict aliasing ruleにより未定義であるので良くない。ここで示しているコードは、インテルCPUのシステムでVisual C++ 2013、GCC 4.9.3で動作確認済み。
- ^ intel Corei5プロセッサ、Clang(clang-1000.11.45.5, docker gcc 6.3.0 20170516で確認。記録は「Endian確認プログラム、64bitを追加。」https://qiita.com/kaizen_nagoya/items/f55112ca74936fd30fcb
- ^ 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