『Cプログラミング専門課程』目次第4章メモリ

4.2 バイトオーダー (1)


整数型(char,short,int,long)のデータも、浮動小数点型(float,double) のデータもメモリに記憶されます。このとき、コンピュータにより記憶のされ 方が異なります。1つのデータが1バイトより長いとき、複数のバイトに記憶 されます。このとき、コンピュータ(より正確にはCPU)により、記憶のされ 方が異なります。このときの記憶のされ方、とくにバイト単位での記憶のされ 方を「バイトオーダー」と呼びます。

次のプログラムは、メモリ上の指定アドレスから指定バイト数だけのメモリ の内容を16進数で表示する関数prmemを用いて、基本データ型がメモリのどこ に確保されているかを調べます。ここで使用しているコンピュータでは、 int 型のサイズは4バイトになっています。

サンプルプログラム


   1: /*  basorder.c  --  基本型のバイトオーダー  */
   2: 
   3: #include        <stdio.h>
   4: 
   5: void    prmem( const void *_p, int n )
   6: {
   7:         const unsigned char     *p = _p;
   8:         char    i, j;
   9: 
  10:         for( i=0 ; i<n ; ++i, ++p ) {
  11:                 printf( " %02x", *p );
  12:         }
  13: }
  14: 
  15: main()
  16: {
  17:         char    c = 0x12;
  18:         short   h = 0x1234;
  19:         long    l = 0x12345678;
  20:         int     i = 0x12345678;
  21: 
  22:         float   f = 2.3;
  23:         double  g = 2.3;
  24:         double  fg;
  25: 
  26:         printf( "char  %p : %02x :", &c, c );
  27:         prmem( &c, sizeof(c) );  printf( "\n" );
  28: 
  29:         printf( "short %p : %02x :", &h, h );
  30:         prmem( &h, sizeof(h) );  printf( "\n" );
  31: 
  32:         printf( "long  %p : %04x :", &l, l );
  33:         prmem( &l, sizeof(l) );  printf( "\n" );
  34: 
  35:         printf( "int   %p : %04x :", &i, i );
  36:         prmem( &i, sizeof(i) );  printf( "\n\n" );
  37: 
  38:         printf( "float %p : %20.16f :", &f, f );
  39:         prmem( &f, sizeof(f) );  printf( "\n" );
  40: 
  41:         printf( "float %p : %20.16f :", &g, g );
  42:         prmem( &g, sizeof(g) );  printf( "\n" );
  43: 
  44:         fg = f;
  45:         printf( "float %p : %20.16f :", &fg, fg );
  46:         prmem( &fg, sizeof(fg) );  printf( "\n" );
  47: 
  48:         printf( "double - float : %g\n", g - fg );
  49: }

メモリ内容を16進数でプリントする関数がprmemです。

   5: void    prmem( const void *_p, int n )
   6: {
   7:         const unsigned char     *p = _p;
  

第1引数の型がvoid型へのポインタであるのは大変重要です。関数prmemはあ らゆる変数や関数のアドレスをパラメータから受け取るので、どんな型でも受 け取れなければいけません。もし関数prmemが

	void    prmem( const unsigned char *_p, int n )
  

と宣言されていたら、unsigned char 型以外の変数のアドレスをパラメータと して渡すとき、毎回 (unsigned char *) をキャストしなければならず、はな はだ面倒です。7行目で void型へのポインタとして受け取ったパラメータを unsigned char型へのポインタにしているのは、16進数でプリントするとき、 signed char型(-128〜+127)ではなく、unsigned char型(0〜+255)と解釈させ るためです。詳しくは「5.6キャスト」で説明します。

実行結果
char  f7fffac7 : 12 : 12
short f7fffac4 : 1234 : 12 34
long  f7fffac0 : 12345678 : 12 34 56 78
int   f7fffabc : 12345678 : 12 34 56 78

float f7fffab8 :   2.2999999523162842 : 40 13 33 33
float f7fffab0 :   2.2999999999999998 : 40 02 66 66 66 66 66 66
float f7fffaa8 :   2.2999999523162842 : 40 02 66 66 60 00 00 00
double - float : 4.76837e-08

long型の4バイトのデータは、

(680X0系)

となっています。中央の 12345678 は整数値の16進数表示で、この値は変数の アドレス(f7fffac0番地)から順に、各バイトに、12、34、56、78が入ってい ます。f7fffac0番地には12、f7fffac3番地には78が入っています。このように 最上位バイト側から順にメモリに入っているのが「正順」のバイトオーダーで す。あるいは、最上位側が最初にくるので、MSB First (Most Significant Byte First)とか、Big Endianとも言います。

しかし、このようにメモリに入っているのは、680X0系、SPARC系などのコン ピュータの場合で、パソコンで主流の80X86系では、同じlong型の値12345678も 異なった方法でメモリに入っています。

(80X86系)

つまり、80X86系では、long型の変数値の最下位バイトが最初のアドレスに、 最上位バイトが最後のアドレスに記憶されます。このように最下位バイト側か ら順にメモリに入っているのが「逆順」のバイトオーダーです。当然別の言い 方があり、最下位側が最初にくるので、LSB First (Least Significant Byte First)とか、Little Endianとも言います。

最上位から順にメモリに入れるのと、最下位から入れるのでは全くの逆です が、通常プログラムをしている場合、この違いを考慮する必要はありません。 パソコンとUNIXマシンをネットワークで繋いで、互いにデータを交換するよう な、 80X86系と680X0系のコンピュータを混在させて使用する場合には注意す る必要があります。

⇒⇒⇒⇒次ページへ


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング専門課程』目次第4章メモリ