リトルエンディアンとは?データをメモリに格納する際の基本を押さえる

専門用語
スポンサーリンク
スポンサーリンク

リトルエンディアンの概要

リトルエンディアンは、データをメモリに格納する際のバイト順序の一種です。
バイト順序とは、複数バイトで構成されるデータをどのようにメモリに配置するかの方法を指します。データには例えば、32ビット(4バイト)の整数や64ビット(8バイト)の浮動小数点数などがありわけですが、それらのデータをどのような順番で並べていくか、という事についての決まり事です。

整数の例

例えば、32ビットの整数42をリトルエンディアン形式でメモリに格納する場合、42を16進数で表すと0x2Aになります。
16進数についての詳細は↓の記事をご参照ください。


これを4バイトリトルエンディアン形式で格納すると、以下のようになります。

まず、42の16進数表現である0x2Aをバイトごとに分割します。
整数42は32ビット(4バイト)のデータ型ですので、0x2A 0x00 0x00 0x00となります。
リトルエンディアン形式では、最下位バイトの0x2Aがメモリの先頭に配置され、その後に0x00が続きます。したがって、メモリには次のように格納されます:0x2A 0x00 0x00 0x00。

浮動小数点数の例

リトルエンディアン形式を理解するためのもう一つの例として、64ビットの浮動小数点数3.14159を考えてみます。
この値をリトルエンディアン形式でメモリに格納する場合、3.14159の64ビット表現は次のようになります:0x1F 0x85 0xEB 0x51 0xB8 0x1E 0x09 0x40。

この場合も、最下位バイト0x1Fがメモリの先頭に配置され、次に0x85が続き、最上位バイト0x40が最後に配置されます。

浮動小数点数のメモリ表現(3.14159の例)

浮動小数点数3.14159が64ビットdouble型)のメモリ表現として0x1F(31) 0x85(133) 0xEB(235) 0x51(81) 0xB8(184) 0x1E(30) 0x09(9) 0x40(64)になる理由を詳しく説明します。

16進数になじみのない方向けに()で10進数表記も併記しました。

IEEE 754標準

double型の浮動小数点数は、IEEE 754標準に従って次のように64ビットで表現されます。

3.14159のIEEE 754表現

  1. 符号ビット(数値の正負を表すビット: 3.14159は正の数なので、符号ビットは0です。
    ※負の数の場合は、符号ビットは1になります。
  2. 指数部(数値の大きさを表すビット: 3.14159を2進数に変換し、正規化プログラムが取り扱うルールに則って値を整える作業)します。

3.14159の2進数表現はおおよそ次のようになります

11.001001000011111101111100111011

正規化すると:

1.1001001000011111101111100111011 × 2^1

この指数は1なので、バイアス1023(2の10乗 – 1)を加えます。

1 + 1023 = 1024

1024の2進数表現は

10000000000

仮数部(または有効数字部)(数値の精度を表すビット: 仮数部は正規化された後の小数部分です:

1001001000011111101111100111011

これを64ビットのIEEE 754標準に基づいて配置すると次のようになります:

符号ビット(数値の正負を表すビット) | 指数部(数値の大きさを表すビット)(11ビット) | 仮数部(または有効数字部)(数値の精度を表すビット)(52ビット)
0           | 10000000000(1024)        | 1001001000011111101111100111011(残りは0で埋める)

16進数表現への変換

これを16進数に変換します。

  • 符号ビット(数値の正負を表すビット): 0
  • 指数部(数値の大きさを表すビット): 10000000000 = 0x400(16進数) = 1024(10進数
  • 仮数部(または有効数字部)(数値の精度を表すビット): 1001001000011111101111100111011 = 0x921FB54442D18(16進数) = 1019660462256671288(10進数

したがって、64ビット配列は次のようになります:

0100 0000 0000 1001 0010 0001 1111 1011 1101 1111 0011 1011 0000 0000 0000 0000

リトルエンディアン形式への変換

リトルエンディアン形式では、バイトオーダーが逆になるため次のようになります:
※()内は対応する10進数表記です。

18(24) 2D(45) 44(68) 54(84) FB(251) 21(33) 09(9) 40(64)

よって、3.14159の64ビットにおけるリトルエンディアン形式の表現は:

0x18(24) 0x2D(45) 0x44(68) 0x54(84) 0xFB(251) 0x21(33) 0x09(9) 0x40(64)

となります。

char型について

char型は、1バイト(8ビット)のデータ型で、整数としても文字としても扱うことができます。
char型リトルエンディアン表現について考えると、実際にはchar型のサイズが1バイトであるため、リトルエンディアンやビッグエンディアンの違いが存在しません。
なぜなら、1バイトはそれ自体で完結しており、バイト順序を気にする必要がないからです。

例えば、文字’M’のASCIIコードは77(10進数)で、16進数表記では0x4Dです。これをメモリに格納すると、次のようになります。

  • char c = 'M'; とする場合、メモリにはそのまま0x4D(77)が格納されます。

例えば、文字’M’のASCIIコードは77(10進数)で、16進数表記では0x4Dです。これをメモリに格納すると、次のようになります。

  • char c = 'M'; とする場合、メモリにはそのまま0x4D(77)が格納されます。

char型の例

以下は、char型変数に文字を格納し、そのメモリ表現を確認する例です。

char c = 'M';
Print((int)c);  // 77が出力される

このコードでは、文字’M’をchar型変数代入しています。

これは、実際には’M’のASCIIコードである77が変数cに格納されることを意味します。

char型を用いることで、文字とそのASCIIコードを相互に扱うことができます。

short型について

Short型は16ビット(2バイト)の整数型です。リトルエンディアン形式では、最下位バイトが先頭に格納され、最上位バイトが最後に格納されます。

例えば、16ビット整数258(0x0102)をリトルエンディアン形式でメモリに格納する場合:

short型の例

以下は、Short型変数に整数を格納し、そのメモリ表現を確認する例です。

short s = 258;
// メモリ表現:0x02 0x01
Print("s[0] = ", (int)((uchar*)&s)[0]);  // 2が出力される
Print("s[1] = ", (int)((uchar*)&s)[1]);  // 1が出力される

このコードでは、整数258をShort型変数代入しています。

リトルエンディアン形式では、最下位バイト0x02が先頭に、最上位バイト0x01が最後に格納されます。

long型について

long型は32ビット(4バイト)の整数型です。リトルエンディアン形式では、最下位バイトが先頭に格納され、最上位バイトが最後に格納されます。

例えば、32ビット整数305419896(0x12345678)をリトルエンディアン形式でメモリに格納する場合:

long型の例

以下は、long型変数に整数を格納し、そのメモリ表現を確認する例です。

long l = 305419896;
// メモリ表現:0x78 0x56 0x34 0x12
Print("l[0] = ", (int)((uchar*)&l)[0]);  // 120が出力される -> 0x78
Print("l[1] = ", (int)((uchar*)&l)[1]);  // 86が出力される -> 0x56
Print("l[2] = ", (int)((uchar*)&l)[2]);  // 52が出力される -> 0x34
Print("l[3] = ", (int)((uchar*)&l)[3]);  // 18が出力される -> 0x12

float型について

float型は32ビット(4バイト)の浮動小数点数型で、IEEE 754標準に従ってメモリに格納されます。リトルエンディアン形式では、バイトオーダーが逆になります。

例えば、値が1.0の場合、IEEE 754形式に基づいてメモリに格納されます。

1.0のIEEE 754表現は次のようになります:

  • 符号ビット: 0
  • 指数部: 127(バイアスを考慮)
  • 仮数部: 0

これを16進数に変換すると:

  • 0x3F800000(ビッグエンディアン形式)

リトルエンディアン形式では、0x00 0x00 0x80 0x3Fと格納されます。

float型の例

以下は、float型の変数に値を格納し、そのメモリ表現を確認する例です。

float f = 1.0;
// メモリ表現:0x00 0x00 0x80 0x3F
Print("f[0] = ", (int)((uchar*)&f)[0]);  // 0が出力される -> 0x00
Print("f[1] = ", (int)((uchar*)&f)[1]);  // 0が出力される -> 0x00
Print("f[2] = ", (int)((uchar*)&f)[2]);  // 128が出力される -> 0x80
Print("f[3] = ", (int)((uchar*)&f)[3]);  // 63が出力される -> 0x3F

このコードでは、値1.0をfloat型の変数代入しています。リトルエンディアン形式では、最下位バイト0x00が先頭に、最上位バイト0x3Fが最後に格納されます。

このように、各データ型についてリトルエンディアン形式でのメモリ表現を確認することができます。

タイトルとURLをコピーしました