64bit OS と 32bit OS でのデータ型の相違一覧

Perl-XS なモジュールを 64bit OS で使っていると、ごく希に変数型サイズが問題で不具合を経験することがあります。例えば、メジャーどころで言えば、日本語係り受け解析器のCaboCha/南瓜を例に挙げますと、

src/common.h の103〜107行目

 static inline void replaceString (std::string &s, const std::string &src, const std::string &dst)
{
unsigned int pos = s.find (src);
if (pos != std::string::npos) s.replace (pos, src.size(), dst);
}
- スポンサーリンク -

の unsigned int pos = s.find (src); の部分ですが、32bit 環境では問題は発生しませんが、64bit 環境ではポインタ型のサイズが異なって正常動作しなくなります。正しくは、STL(Standard Template Library) の仕様通り、size_t で受け取る必要があって、

 static inline void replaceString (std::string &s, const std::string &src, const std::string &dst)
{
size_t pos = s.find (src);
if (pos != std::string::npos) s.replace (pos, src.size(), dst);
}

になるわけです。(これはかなり前のネタですが、既に作者の方とやりとりさせて頂いています)。

その他、CPAN にあがっているもので記憶にあるのは暗号モジュールの、Crypt-Rijndael-0.05 も 64bit で不具合がありました。具体的には、

rijndael.h の 30〜31 行目

typedef unsigned long UINT32;
typedef unsigned char UINT8;

の typedef unsigned long UINT32;  が不具合の原因です。64bit 環境では long 型は 8byte なので UINT32 つまり 4byte では無くなるわけです。

このような不具合を出さないためには、まず変数型のサイズを把握しておく必要があります。
自分の環境で変数のサイズを知るのは簡単で、次のプログラムをコンパイルして実行すればOKです。

#include <stdio.h>

int main(void)
{
printf("char : %d\n", sizeof(char));
printf("short : %d\n", sizeof(short));
printf("int : %d\n", sizeof(int));
printf("long : %d\n", sizeof(long));
printf("float : %d\n", sizeof(float));
printf("double: %d\n", sizeof(double));
printf("long long : %d\n", sizeof(long long));
printf("long double: %d\n", sizeof(long double));
return 0;
}

ちなみに、x86 系 Linux の 32bit と 64bit での結果はこんな感じになります。黄色の部分がサイズが異なる部分です。

変数の型 32bit 64bit
char 1 byte 1 byte
short 2 byte 2 byte
int 4 byte 4 byte
long 4 byte 8 byte
float 4 byte 4 byte
double 8 byte 8 byte
long long 8 byte 8 byte
long double 12 byte 16 byte

もっともこれは x86 系 Linux の 32bit と 64bit の比較をしただけなので、Sparc 系の cpu では違った結果になると思います。ポインターを操作する場合は、環境依存しないように sizeof 関数でサイズを取得して、size_t 型の変数で値を受け取って操作するのがベターと思います。

- スポンサーリンク -