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

従来の32ビット環境に慣れてしまったプログラマがしばしば犯してしまうミスを交えつつ、32ビット環境から64ビット環境へ移行する際に注意すべき代表的なC言語のプログラミング例を紹介しよう。(特集:64ビットコンピューティング最前線)

» 2005年06月14日 00時00分 公開
[C MAGAZINE]

C MAGAZINE 2004年10月号第3特集「64ビットコンピューティング」より転載

64ビット環境へ移行する際の注意点

 ここでは、従来の32ビット環境に慣れてしまったプログラマがしばしば犯してしまうミスを交えつつ、32ビット環境から64ビット環境へ移行する際に注意すべき代表的なC言語のプログラミング例を紹介します。

 もちろん、32ビット環境でプログラムを書いたことのないプログラマにも有用な情報です。

ポインタをint型やlong型変数に代入しない

 ポインタをint型やlong型変数に代入し、それを操作してはいけません。

 アセンブラまたはインラインアセンブラを使った経験のあるプログラマは、C言語のポインタを整数型変数に代入してアドレスの計算を行うようなコードを書くことがあります。たとえば、List1のようなコードです。

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型が混在した計算に気をつける

 データモデルの違いによってlong型とint型の大きさが異なる場合があることに注意してください。

 ILPやLLPのプログラミングデータモデルは、

sizeof(long) == sizeof(int)

ですが、64ビットプログラミングでの移植性をより高めたい場合は、この関係を仮定してはいけません。Table 6のとおり、LP64のプログラミングデータモデルが、

sizeof(long) != sizeof(int)

となっているからです。

Table 6 sizeof(long)とsizeof(int)の関係
データモデル sizeof(long) 関係 sizeof(int)
ILP32 32ビット == 32ビット
LLP64 32ビット == 32ビット
LP64 64ビット != 32ビット
ILP64 64ビット == 64ビット

 とくに、long型とint型が混在した演算では、中間結果をうっかりint型の変数に格納して上位ビットを欠落させてしまわないよう、十分に気をつける必要があります。

 List2に型のデータサイズとデータモデルを表示するプログラムの例を示します。その実行結果をFig.2に示します。

List2 型のサイズとデータモデルを表示するプログラム
#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]
    );
}

Fig. 2 Fig.2 List2の実行例
       1|2|3 次のページへ

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

注目のテーマ