特集
» 2005年06月14日 00時00分 公開

64ビットコンピューティング最前線:64ビットプログラミングのポイント (3/3)

[C MAGAZINE]
前のページへ 1|2|3       

アライメント(Alignment)に気をつける

 多くのコンピュータは、アドレスの最下位ビットが「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バイト離れた場所に配置されます。

Fig.3 Fig.3 データモデルの違いによる構造体のアライメント

 それに対し64ビット環境では、val_pが8バイトなので8バイト境界に置かれることが多く、先のコードを64ビットの境界でコンパイルすると、val_cとval_pは通常8バイト離れます(Fig. 3の下の図)。したがって、両変数の間隔を「何バイト」と決めつけているようなプログラムは、それぞれの環境でうまく動いてくれないことになります[注3]。なお、構造体のアライメントはコンパイラのオプションで変更できる場合があります。しかし、プログラムのパフォーマンスやポータビリティを高めるためには、できるだけアライメントの影響を受けないような構造体の配列にしておくことが望ましいといえます。

Tips5 Visual C++ .NETで追加されたコンパイラ警告メッセージ:C4312
  Visual C++ .NET上で、32ビットのintまたはlongを64ビットポインタにキャストしようとすると、C4312の警告メッセージが出力されます。これは、ポインタの長さと変数の長さが合わないことが原因で、プログラムを64ビット環境へ移行するにあたって、プログラマが見落とさないようにするための警告です。
  この警告を表示しないようにするには、(あまりお勧めしませんが)型の長さが合った変数へキャストするか、コンパイラオプションの/Wp64(64ビット移植への対応)を無効にします。  ちなみに、C4312をヘルプで調べてみると、次のようなコメントが掲載されています。
「コンパイラの警告(レベル1)C4312 ’variable’: ’type’からより大きいサイズの’type’へ変換します。 64ビットの整数に対して32ビットの値の割り当てを試みました。たとえば、32ビットintまたは32ビットlongを64ビットポインタにキャストしています。」

前のページへ 1|2|3       

Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.

注目のテーマ