従来の32ビット環境に慣れてしまったプログラマがしばしば犯してしまうミスを交えつつ、32ビット環境から64ビット環境へ移行する際に注意すべき代表的なC言語のプログラミング例を紹介しよう。(特集:64ビットコンピューティング最前線)
ここでは、従来の32ビット環境に慣れてしまったプログラマがしばしば犯してしまうミスを交えつつ、32ビット環境から64ビット環境へ移行する際に注意すべき代表的なC言語のプログラミング例を紹介します。
もちろん、32ビット環境でプログラムを書いたことのないプログラマにも有用な情報です。
ポインタをint型やlong型変数に代入し、それを操作してはいけません。
アセンブラまたはインラインアセンブラを使った経験のあるプログラマは、C言語のポインタを整数型変数に代入してアドレスの計算を行うようなコードを書くことがあります。例えば、List1のようなコードです。
long a[N]; long *p; long addr; ... addr = (long) a; addr += sizeof(long) * x; /* a[x]? */ p = (long*) addr; /* LLPデータモデルの場合NG */ /* LP,ILPデータモデルの場合OK */
このコードは、従来の32ビットプログラミングデータモデル上では正しく動作しますが、64ビットプログラミングデータモデル上ではポインタをint型にキャストしたとき、アドレスの上位ビットが失われてしまいセグメントフォルト[注2]などを引き起こしてしまう可能性があります。
また、C言語では、データ領域を動的に確保するためmalloc関数がよく用いられます。malloc関数の戻り値の型がvoid*であるという点に注意すれば、戻り値をint型で受け取ってはいけないということはすぐにわかるでしょう。このような関数では、必ずポインタ型を用いて受けるように注意してください。
64ビットのWindows環境では、新しいデータ型であるLONG_PTRなどを使うようにします。
データモデルの違いによってlong型とint型の大きさが異なる場合があることに注意してください。
ILPやLLPのプログラミングデータモデルは、
sizeof(long) == sizeof(int)
ですが、64ビットプログラミングでの移植性をより高めたい場合は、この関係を仮定してはいけません。Table 6のとおり、LP64のプログラミングデータモデルが、
sizeof(long) != sizeof(int)
となっているからです。
データモデル | sizeof(long) | 関係 | sizeof(int) |
---|---|---|---|
ILP32 | 32ビット | == | 32ビット |
LLP64 | 32ビット | == | 32ビット |
LP64 | 64ビット | != | 32ビット |
ILP64 | 64ビット | == | 64ビット |
Table 6 sizeof(long)とsizeof(int)の関係 |
とくに、long型とint型が混在した演算では、中間結果をうっかりint型の変数に格納して上位ビットを欠落させてしまわないよう、十分に気をつける必要があります。
List2に型のデータサイズとデータモデルを表示するプログラムの例を示します。その実行結果をFig.2に示します。
#define _16BIT 2 #define _32BIT 4 #define _64BIT 8 #define N_MODELS 5 #define N_TYPES 3 enum { TYPE_INT = 0, TYPE_LONG = 1, TYPE_POINTER = 2, }; void datamodel() { const char *modelstr[N_MODELS + 1] = { "LP32", "ILP32", "LP64", "LLP64", "ILP64", "unknown" }; const int modelsize[N_MODELS][N_TYPES] = { { _16BIT, _32BIT, _32BIT }, { _32BIT, _32BIT, _32BIT }, { _32BIT, _64BIT, _64BIT }, { _32BIT, _32BIT, _64BIT }, { _64BIT, _64BIT, _64BIT }, }; int sizeofint, sizeoflong, sizeofpointer, model; sizeofint = sizeof(int); sizeoflong = sizeof(long); sizeofpointer = sizeof(void*); for( model = 0; model < N_MODELS; model++ ) { if ( sizeofint == modelsize[model][TYPE_INT] && sizeoflong == modelsize[model][TYPE_LONG] && sizeofpointer == modelsize[model][TYPE_POINTER] ) break; } printf( "sizeof(int) = %dbytes\n" "sizeof(long) = %dbytes\n" "sizeof(ptr) = %dbytes\n" "---------------------\n" "data model = %s\n" , sizeofint , sizeoflong , sizeofpointer , modelstr[model] ); }
Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.