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

4.3 アラインメント


実行結果での変数のアドレスは、16進数表記すると最後の桁が、0、4、8、c になっていました。ということは、アドレスは4の倍数になっているのです。 果たしてこれは偶然なのでしょうか、それとも必然なのでしょうか。各変数の 先頭アドレスに注意して調べてみましょう。

サンプルプログラム

   1: /*  alinment.c  --  アラインメント  */
   2: 
   3: #include        <stdio.h>
   4: 
   5: typedef struct {
   6:         char    ch;
   7:         double  d1;
   8:         float   fl;
   9:         short   sh;
  10:         int     in;
  11:         long    ln;
  12: } testcell;
  13: 
  14: char            c1;
  15: char            ch2[2];
  16: char            ch3[3];
  17: double          d;
  18: testcell        t;
  19: char            c2;
  20: char            c3;
  21: long            ln;
  22: float           fl;
  23: char            *p;
  24: 
  25: main()
  26: {
  27:         printf( "char    c1     %2d : %p\n", sizeof(c1), &c1 );
  28:         printf( "char    ch2[2] %2d : %p\n", sizeof(ch2),ch2 );
  29:         printf( "char    ch3[3] %2d : %p\n", sizeof(ch3),ch3 );
  30:         printf( "double  d      %2d : %p\n", sizeof(d),  &d );
  31:         printf( "testcell  t    %2d : %p\n", sizeof(t),  &t );
  32:         printf( "char    c2     %2d : %p\n", sizeof(c2), &c2 );
  33:         printf( "char    c3     %2d : %p\n", sizeof(c2), &c3 );
  34:         printf( "long    ln     %2d : %p\n", sizeof(ln), &ln );
  35:         printf( "float   fl     %2d : %p\n", sizeof(fl), &fl );
  36:         printf( "char    *p     %2d : %p\n", sizeof(p),  &p );
  37: 
  38:         printf( "\n構造体\n" );
  39:         printf( "char    ch     %2d : %p\n", sizeof(t.ch), &t.ch );
  40:         printf( "double  d1     %2d : %p\n", sizeof(t.d1), &t.d1 );
  41:         printf( "float   fl     %2d : %p\n", sizeof(t.fl), &t.fl );
  42:         printf( "short   sh     %2d : %p\n", sizeof(t.sh), &t.sh );
  43:         printf( "int     in     %2d : %p\n", sizeof(t.in), &t.in );
  44:         printf( "long    ln     %2d : %p\n", sizeof(t.ln), &t.ln );
  45: }

実行結果

char    c1      1 : 4250
char    ch2[2]  2 : 4284
char    ch3[3]  3 : 4286
double  d       8 : 4248
testcell  t    32 : 4260
char    c2      1 : 4252
char    c3      1 : 4254
long    ln      4 : 4280
float   fl      4 : 425c
char    *p      4 : 4258

構造体
char    ch      1 : 4260
double  d1      8 : 4268
float   fl      4 : 4270
short   sh      2 : 4274
int     in      4 : 4278
long    ln      4 : 427c

メモリ上のアドレスの順番ですが、宣言した順序になっていません。どうも 適当な、都合の良い順番に並べ替えてしまうようです。

しかし、構造体の中は、宣言した順番に並んでいます。でも、途中に詰め物 (パディング)があり、それぞれのメンバーは、その型により、4の倍数とか8 の倍数のアドレスから入っているようです。

これには、次のような理由があります。

long型のために4バイトの連続した領域をメモリ上に確保したいとき、必ず 4の倍数のアドレスから4バイトという確保しかできないコンピュータがあり ます。また、short型の2バイトの場合も、必ず2の倍数のアドレスから2バ イトという確保しかできないものがあります。このように、複数バイトに渡る データを確保するとき、任意のアドレスから割り当てることができず、データ の型(サイズ)により、2の倍数、4の倍数、8の倍数のように対応する2の ベキ乗の倍数のアドレスからメモリを割り当てることを、アラインメント(境 界整列)といいます。

アラインメントには実にさまざまなレベルがあります。コンピュータのハー ドウェアで完全に決まっているものもあります。ハードウェア的には、どのア ドレスからデータを入れても全く構わないのですが、より高速に処理するため にコンパイラ(あるいはリンカやローダ)が自動的にアラインメントするもの もあります。さらに、コンパイル時の指定でアラインメントを行なったり行な わなかったりできるものもあります。

メモリとCPU間をデータが動き回りますが、このときに一度に送ることがで きる単位が16ビット(2バイト)だったり32ビット(4バイト)だったり色々 あります。16ビットコンピュータ、32ビットコンピュータというときの何ビッ トというのがこの一度に送ることができるビット数です。当然一度に送れる量 が増えると、処理速度が向上します。つまり、高性能コンピュータという訳で す。

アラインメントのない32ビットコンピュータで4バイトのlong型変数をアク セスするとき、4バイトはどこから始まっていても構いません。もし、 4286 番地という4バイトワード境界にまたがるような変数は、データアクセスがワー ド境界で分断され、2回に分けて行なわれます。もし、4288番地からの4バイ トに入っていれば、1度にアクセスでき、処理が高速になります。したがって、 たとえハードウェア的にはアラインメントがないコンピュータでも、より高速 に実行するために、あたかもアラインメントがあるかのようにコンパイルする ことがあります。

*常識*
  • 変数は宣言順に確保されるとは限らない。
  • 変数と変数の間にはすき間があるかもしれない。

⇒⇒⇒⇒4.4 型の変換 へ


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