技術(非IT系)

ビッグエンディアンとリトルエンディアンの違いは?覚え方や具体例も解説!(バイトオーダー・変換方法・ネットワークバイトオーダー・CPUアーキテクチャなど)

ビッグエンディアンとリトルエンディアンの違い
当サイトでは記事内に広告を含みます

ビッグエンディアンとリトルエンディアンの違いは?覚え方や具体例も解説!(バイトオーダー・変換方法・ネットワークバイトオーダー・CPUアーキテクチャなど)

プログラムで整数値やバイナリデータを扱っていると、同じ数値のはずなのに表示結果が大きく変わることがあります。

その原因として代表的なのが、複数バイトのデータを並べる順番であるエンディアンです。

ファイル形式、ネットワーク通信、組み込み開発、メモリ解析などでは、バイトオーダーの理解が不具合の予防につながります

ビッグエンディアンとリトルエンディアンの違い

ビッグエンディアンとリトルエンディアンの違い

それではまず、ビッグエンディアンとリトルエンディアンの違いについて解説していきます。

数値そのものではなく並び順の違い

エンディアンとは、2バイト以上で構成される数値をメモリや通信データへ保存するとき、どのバイトから先に並べるかを示す考え方です。

たとえば16進数で12345678という4バイトの値がある場合、各バイトは12、34、56、78に分けられます。

ビッグエンディアンでは最上位バイトである12を先頭に置き、12、34、56、78の順に格納します。

一方のリトルエンディアンでは最下位バイトである78を先頭に置くため、78、56、34、12という並びになります。

つまり、データの意味である数値は同じでも、メモリ上の見え方が逆になる点が大きな違いです。

項目 ビッグエンディアン リトルエンディアン
先頭に置くバイト 最上位バイト 最下位バイト
12345678の格納例 12 34 56 78 78 56 34 12
人間の表記との近さ 通常の16進数表記に近い 逆順に見えやすい
代表的な利用場面 ネットワーク通信 PC向けCPUのメモリ処理

バイトオーダーが問題になるデータ型

エンディアンの違いが現れるのは、1バイトより大きいデータ型です。

8ビットのunsigned charのように1バイトだけで表される値には、前後を入れ替える対象がないため、バイトオーダーは関係しません。

16ビット整数、32ビット整数、64ビット整数、浮動小数点数、ポインタ値などでは順番が重要になります。

画像ファイルのヘッダー、音声データ、センサー値、データベースのバイナリ列にも複数バイトの値は含まれます。

データを読み込んだ時点で桁違いの値になった場合は、型のサイズだけでなく読み取り側と書き込み側のエンディアンが一致しているかを確認するとよいでしょう。

ビッグとリトルという名称の由来

ビッグエンディアンとリトルエンディアンという言葉は、小説ガリヴァー旅行記に登場する卵の割り方に由来します。

卵の大きい端から割る人々と、小さい端から割る人々が対立する話を、コンピューター分野のバイト順序になぞらえた表現です。

大きい桁を先に置く方式がビッグエンディアンであり、小さい桁を先に置く方式がリトルエンディアンです。

名称は少しユニークですが、実務ではデータ互換性を左右する重要な仕様になります。

ビッグエンディアンは上位バイトから、リトルエンディアンは下位バイトから並べる方式です。

異なる環境でバイナリデータを受け渡す場合、バイトオーダーの取り決めを省略しないことが大切です。

覚え方と16進数による具体例

続いては、覚え方と具体的なバイト列を確認していきます。

大きい桁から読むビッグエンディアン

ビッグエンディアンは、数値を左から読んだときの並びと同じと覚えると理解しやすくなります。

16進数の12345678なら、最も重みの大きい12が先頭です。

紙に書いた数値の見た目とメモリ上の並びが近いため、バイナリダンプを読む場面でも直感的に把握しやすい特徴があります。

英語のbigは大きいという意味なので、大きい位が先に来る方式と結び付ける方法が有効です。

小さい桁から置くリトルエンディアン

リトルエンディアンは、小さい位のバイトを先頭に置く方式です。

12345678という値では、最も小さい位にある78が最初に配置されます。

littleを小さいと捉え、小さい桁がリードすると覚えれば混同を減らせるでしょう。

ただし、数値の各桁を一文字ずつ反転するわけではありません。

入れ替わる単位は16進数2桁分の1バイトごとのまとまりである点に注意が必要です。

32ビット値が12345678の場合の格納例です。

ビッグエンディアンでは12 34 56 78となり、リトルエンディアンでは78 56 34 12となります。

日付や文字列と混同しない考え方

年月日を年、月、日の順に書くか、日、月、年の順に書くかという話は、エンディアンと似て見える場合があります。

しかしエンディアンは、原則として数値を構成するバイトの物理的な並び順を扱う技術用語です。

UTF-8のような可変長文字列は、多くの場合に文字単位で処理されるため、整数のバイトオーダーとは別に考えます。

UTF-16やUTF-32ではエンディアンの影響を受けることがあり、BOMと呼ばれる識別情報が使われるケースもあります。

対象が整数なのか、文字コードなのか、ファイル構造なのかを切り分けることが、正確な判断への近道です。

CPUアーキテクチャと利用環境

続いては、CPUアーキテクチャと利用環境の関係を確認していきます。

x86系CPUで多いリトルエンディアン

パソコンやサーバーで広く使われるx86、x64系のCPUは、基本的にリトルエンディアンです。

Windowsパソコンでメモリダンプを確認すると、複数バイト整数が逆順に見えることが多いのはこのためです。

Intel系だけでなく、一般的なPCソフトウェアではリトルエンディアンを前提にしたコードやファイル処理も少なくありません。

ただし、アプリケーション内部で扱うバイト列が必ずリトルエンディアンとは限りません。

通信規約やファイル仕様がビッグエンディアンを指定していれば、CPUの方式とは別に変換処理が必要です。

ARMとバイエンディアンの特徴

ARMアーキテクチャは、実装や動作モードによって複数のバイトオーダーを扱える設計を持っています。

そのため、ARM搭載機器だから一律にどちらかと決め付けるのではなく、OSや対象システムの仕様を確認する姿勢が重要です。

現在のスマートフォンや一般的な組み込みLinux環境では、リトルエンディアンで使われる場面が多く見られます。

一方で、特殊なハードウェア、古いシステム、通信機器では別の前提が残っていることもあります。

CPUの種類だけを根拠にデータ形式を判断しないことが、安全な実装につながります。

ファイル形式ごとに異なる保存方式

ファイル形式には、ビッグエンディアンとリトルエンディアンのどちらを使用するかが仕様として定められていることがあります。

代表例として、TIFF形式にはバイトオーダーを示す情報があり、読み込み側はその指定に従って数値を解釈します。

WAV形式のようにリトルエンディアンを中心とする形式もあれば、ネットワーク由来の仕様でビッグエンディアンを採用するものもあります。

拡張子だけでは判断せず、対象フォーマットの公式仕様で整数フィールドの並びを確認することが確実です。

対象 よく見られる方式 確認時のポイント
x86とx64環境 リトルエンディアン メモリ上の整数値
ネットワーク通信 ビッグエンディアン プロトコル仕様
ARM搭載機器 環境によって異なる OSとコンパイラ設定
バイナリファイル 形式ごとに異なる ファイル仕様書

ネットワークバイトオーダーの基礎

続いては、ネットワークバイトオーダーの基礎を確認していきます。

通信規約で採用されるビッグエンディアン

ネットワークバイトオーダーとは、ネットワーク上で複数バイトの数値を送受信するときの標準的な並び順です。

一般にネットワークバイトオーダーはビッグエンディアンを指します。

送信元と受信先のCPUが異なる方式を採用していても、通信時の表現を統一すれば、ポート番号やパケット長を正しく解釈できます。

インターネットプロトコルの世界では、ホスト側の方式と通信上の方式を分けて考えることが基本になります。

ホストバイトオーダーとの違い

ホストバイトオーダーは、現在プログラムが実行されているコンピューターのCPUが使う並び順です。

たとえばx64パソコンではホストバイトオーダーがリトルエンディアンであることが一般的です。

そのパソコンからネットワークへ16ビットや32ビットの値を送る場合、ネットワークバイトオーダーへ変換してから送信します。

受信側では逆に、通信データをホストバイトオーダーへ戻して利用します。

この変換を忘れると、80番ポートが20480のような別の値として扱われる可能性があります。

ネットワークバイトオーダーはビッグエンディアンです。

PC側がリトルエンディアンでも、通信パケット内の整数はプロトコルの規定に合わせて変換します。

プロトコル解析での確認方法

パケットキャプチャーを読むときは、ツールが人間向けに変換済みの値を表示しているのか、生の16進データを表示しているのかを見分ける必要があります。

生データとして00 50が並んでいれば、ネットワークバイトオーダーでは16進数0050、つまり10進数80です。

これをリトルエンディアンとして誤って読めば5000となり、ポート番号の意味が変わってしまいます。

障害調査では、パケット仕様、バイト列、表示上の数値を順番に照合すると、変換漏れを発見しやすくなります。

変換方法とプログラミング実装

続いては、バイトオーダーの変換方法と実装上の注意点を確認していきます。

C言語で使われる変換関数

C言語やC++のネットワークプログラミングでは、ホストとネットワークの間を変換する関数がよく利用されます。

16ビット値にはhtonsとntohs、32ビット値にはhtonlとntohlが代表的です。

hはhost、nはnetwork、sはshort、lはlongを表す名称として理解できます。

これらを使えば、実行環境のCPUがどちらの方式でも、ネットワーク仕様に合わせた処理を書きやすくなります。

16ビットのポート番号80をネットワーク送信用に変換する場合、htonsを利用します。

受信した16ビット値をホスト側の整数へ戻す場合はntohsを利用します。

ビットシフトによる手動変換

バイトオーダーを理解するためには、ビットシフトとAND演算による手動変換も役立ちます。

32ビット値では、各バイトを取り出して反対側の位置へ移動させ、OR演算で結合します。

ただし、独自実装では符号付き整数の扱い、型変換、評価順序などで思わぬ不具合が起こることがあります。

標準ライブラリ、コンパイラ組み込み関数、信頼できる既存APIがある場合は、そちらを優先するのが無難でしょう。

変換処理は短く見えても境界条件を含む重要なコードです。

12345678をバイト単位で反転すると78563412になります。

この処理は32ビット全体のビット反転ではなく、4つのバイト位置を交換する操作です。

PythonやJavaScriptでの扱い

Pythonではstructモジュールを使うと、バイト列と数値の変換時にエンディアンを明示できます。

JavaScriptではArrayBufferやDataViewを利用し、読み書きの関数にリトルエンディアンかどうかを指定できる場面があります。

高水準言語でも、バイナリプロトコル、WebAssembly、デバイス通信、独自ファイル形式を扱うときには知識が必要です。

ソースコードに方式を明記し、テスト用の16進データを残しておくと、保守担当者にも意図が伝わります。

不具合を防ぐ確認ポイント

続いては、エンディアンに関する不具合を防ぐ確認ポイントを確認していきます。

仕様書で確認すべき項目

外部システムやデバイスと連携する前には、通信仕様書やファイル仕様書を確認します。

整数のビット幅、符号の有無、バイトオーダー、浮動小数点形式、文字コードは特に重要な項目です。

リトルエンディアンという記載がなくても、低位バイト先行やLSB firstと書かれている場合があります。

反対に、MSB first、network order、big endianといった表現は、上位バイト先行を示すことが多いでしょう。

テストデータで行う相互検証

実装後は、0、1、255、256、65535のように境界が分かりやすい値で検証すると効果的です。

さらに12345678のように各バイトが異なるテスト値を使えば、順序の誤りを見つけやすくなります。

すべてのバイトが00やFFの値だけでは、反転しても見た目が変わらず、バグを見逃すおそれがあります。

各バイトに異なる値を入れたテストケースを、単体テストと結合テストの両方に用意すると安心です。

浮動小数点と構造体の注意点

浮動小数点数は整数よりも構造が複雑であり、単純なバイト反転だけでは解決しないケースがあります。

また、C言語の構造体はメンバー間にパディングが入る可能性があるため、そのまま通信データへコピーする設計には注意が必要です。

通信データはフィールドごとに明示的にシリアライズし、受信側で復元する方式が理解しやすくなります。

エンディアンの変換とメモリ配置の問題を分けて考えることが、堅牢なバイナリ処理につながります。

エンディアンの不具合は、値が少しずれるのではなく、大幅に異なる数値として現れることがあります。

仕様確認、変換APIの利用、異なるバイト値によるテストを組み合わせることが有効です。

ビッグエンディアンとリトルエンディアンのまとめ

ビッグエンディアンは最上位バイトから、リトルエンディアンは最下位バイトから複数バイトの数値を並べる方式です。

PCで広く使われるx86系ではリトルエンディアンが一般的である一方、ネットワークバイトオーダーではビッグエンディアンが採用されます。

ファイル形式やCPUアーキテクチャによって前提が異なるため、データ仕様を確認してから変換する習慣が重要です。

覚え方としては、bigは大きい位が先、littleは小さい位が先と考えると分かりやすいでしょう。

バイナリ通信やファイル解析で予期しない値が出たときは、まずバイトオーダーを疑ってみてください。