リトルエンディアンとビッグエンディアン あなたのパソコンはどっち?【C言語・自作プログラム】【超簡単!】
「自分のパソコンのエンディアンを知りたい!」
そんな方の疑問に答えます。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
・筆者の小話
ある時、私はバイナリ(byteデータ)の音声データを音声に変換していました。
ちゃんとプログラミングを組んでいるはずなのに音声がザーッとしか聞こえない!
そこで出会ったのがエンディアン問題です。
どうやら、バイナリデータはビックエンディアンで格納されており、私のパソコンはリトルエンディアンだったため、データの扱い方に失敗していたようだ。
1週間、ずっとイライラしていた問題が1時間ぐらいで解消されました。
皆さんもお気をつけください!
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
コードが知りたい方は目次のソースコードへ飛んでください!
本記事のテーマ
【完全初心者向け】リトルエンディアンとビッグエンディアンの理解!
自分のCPUのエンディアンを調べるプログラムの作成!
リトルエンディアン・ビックエンディアンとは、
今日のプロセッサの多くはバイトアドレッシング方式と呼ばれる方式でメモリをアクセスしに行きます。この方式は、メモリのデータ幅(箱の大きさ)に関係なく、1バイト単位でアドレスをつけていく方式です。1バイトごとにアドレスをつけていくので、メモリの容量はアドレス空間の大きさと同じです。
プログラム中では、数値演算はレジスタ長を単位として行われます。32ビットプロセッサなら、一度に32ビットの数値が取り扱います。これは、多くのプロセッサは数値演算を行うとき、レジスタを用いるためです(Load/Store architecture)。一方で、バイトアドレッシング方式の場合 データの格納単位はバイトなので、レジスタの内容をメモリに書き出すときにはバイト単位で行います。すると、次の問題が起こります。
「32ビットは4バイトあるけど、どの順番でメモリに書けばいいの?」
このとき、「多バイトで構成されるデータをどの順番で格納するか」というのがバイトオーダです。そのため、8ビットメモリと8ビットプロセッサを組み合わせた場合や、ワードアドレッシング方式のプロセッサの場合、バイトオーダはありません(厳密にはウソ)。近年、多くのプロセッサはバイトアドレッシング方式の32ビットプロセッサであるため、バイトオーダの問題はほぼ避けられない問題だと思ってよいでしょう。
ちなみに、バイトオーダのことをエンディアンと呼んだりもします。
(下記サイトから引用)
リトルエンディアン(littele endian)
ー 最下位ビットが存在するbyteを低位のアドレスへ格納していく方式(バイナリダンプでは「逆順」で見える)
ビックエンディアン(big endian)
ー 最上位ビットが存在するbyteを低位のアドレスへ格納していく方式(バイナリダンプでは「正順」で見える)
エンディアン判定プログラム作成!
アルゴリズム
エンディアン判定プログラム作成
1. intで16進数を宣言
2. char型ポインタにintのアドレスを格納
3. charのポインタの値を表示
int型(32bit→4byte)をchar型(8bit→1byte)に分けることで1byteがどう格納されているかが見える!
エンディアン判定プログラム実装!
←int型の16進数を宣言
2. char* src_p;
←char型のポインタを宣言
3. src_p = &src;
←char型ポインタにint型のアドレスを格納
4. printf("0x%x\n", *src_p);
←char型ポインタの中身を表示
code
int src = 0x01234567;
char* src_p;
src_p = &src;
printf("0x%x\n", src);
printf("0x%x\n", *src_p);
printf("0x%x\n", src_p[1]);
出力
0x1234567
0x67
0x45
完成です!
エンディアン判定プログラムを実装しました。
出力を見ると自分のパソコンMacbook pro(CPU=intel)はリトルエンディアンだと分かる。
皆さんも自分のパソコンのエンディアンを確認してみて下さい。
main文を含む全ソースコードは以下に示します。
ソースコード
#include <stdio.h>
void enshu0612(void);
int main() {
enshu0611();
return 0;
}
void enshu0612(void){
int src = 0x01234567;
char* src_p;
src_p = &src;
printf("0x%x\n", src);
printf("0x%x\n", *src_p);
printf("0x%x\n", src_p[1]);
}