64ビットプログラミングのポイント:64ビットコンピューティング最前線(3/3 ページ)
従来の32ビット環境に慣れてしまったプログラマがしばしば犯してしまうミスを交えつつ、32ビット環境から64ビット環境へ移行する際に注意すべき代表的なC言語のプログラミング例を紹介しよう。(特集:64ビットコンピューティング最前線)
アライメント(Alignment)に気をつける
多くのコンピュータは、アドレスの最下位ビットが「1」となる場所を先頭アドレスとして、2バイトの変数をメモリに格納することはできません(最悪の場合、環境によってはアプリケーションがクラッシュしてしまいます)。もし、格納できるとしても、メモリのアクセス効率が極端に悪くなってしまうので、通常は最下位ビットが「0」となるアドレスに変数領域を割り当てるようコンパイラが最適化します。
同様に、4バイトの変数は下位ビットが「01」「10」「11」となる場所には格納できず、「00」となる場所に配置されます。このようにメモリ上でデータの境界がそろえられることを「アライメント(Alignment)」と呼びます。
例えば、List6のような構造体があったとします。また、この構造体cellはメモリ上の0x12345670番地に置かれているものと仮定します。そうすると、構造体のメンバ変数val_cは、0x12345670に置かれます。
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]。なお、構造体のアライメントはコンパイラのオプションで変更できる場合があります。しかし、プログラムのパフォーマンスやポータビリティを高めるためには、できるだけアライメントの影響を受けないような構造体の配列にしておくことが望ましいといえます。
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ビットポインタにキャストしています。」
Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.
