多くのコンピュータは、アドレスの最下位ビットが「1」となる場所を先頭アドレスとして、2バイトの変数をメモリに格納することはできません(最悪の場合、環境によってはアプリケーションがクラッシュしてしまいます)。もし、格納できるとしても、メモリのアクセス効率が極端に悪くなってしまうので、通常は最下位ビットが「0」となるアドレスに変数領域を割り当てるようコンパイラが最適化します。
同様に、4バイトの変数は下位ビットが「01」「10」「11」となる場所には格納できず、「00」となる場所に配置されます。このようにメモリ上でデータの境界がそろえられることを「アライメント(Alignment)」と呼びます。
たとえば、List6のような構造体があったとします。また、この構造体cellはメモリ上の0x12345670番地に置かれているものと仮定します。そうすると、構造体のメンバ変数val_cは、0x12345670に置かれます。
List6 構造体の例 |
struct CELL { char val_c; void* val_p; }; struct CELL cell; |
32ビットのコンピュータでILP32の場合、メンバ変数val_pの長さは4バイトです。しかし、アライメントの影響によって、val_pはval_cに続く領域「0x12345671〜0x12345674」には置くことができず、4バイト境界の「0x12345674〜0x12345677」に置かれることになります。すなわち、val_cとval_pはFig.3の上の図のように、ちょうど4バイト離れた場所に配置されます。
それに対し64ビット環境では、val_pが8バイトなので8バイト境界に置かれることが多く、先のコードを64ビットの境界でコンパイルすると、val_cとval_pは通常8バイト離れます(Fig. 3の下の図)。したがって、両変数の間隔を「何バイト」と決めつけているようなプログラムは、それぞれの環境でうまく動いてくれないことになります[注3]。なお、構造体のアライメントはコンパイラのオプションで変更できる場合があります。しかし、プログラムのパフォーマンスやポータビリティを高めるためには、できるだけアライメントの影響を受けないような構造体の配列にしておくことが望ましいといえます。
|
Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.