ポインタ演算の型にunsigned long型を使ってはいけない

C言語やC++において、ポインターのアドレスを計算する際などに整数に変換する際に往々にしてunsigned long型が使われれることがあるが、これは絶対に行ってはならない。それを行ってしまうと、環境によっては正常に動かないことがあるからである。

32ビット環境では長らく基本的にはメモリーのアドレスとして32ビット分の長さが使われており、その型としてlongがよく使われていたが、64ビット環境への移行時に環境によって以下のように変わっていった。

  • Unix系環境 – int型は32ビット、long型とlong long型は64ビット
  • Windows系環境 – int型とlong型は32ビット、long long型は64ビット

上記のことから、Unix系のみの対応であればlongのままでもアドレスを扱う場合はそれほど問題は無い [1]最も、32ビットであることを前提としていた場合問題となる はずなのだが、Windows系も扱うといった場合、一筋縄ではいかなくなる。

C99以降およびC++11ではアドレスのサイズ分の大きさが保証されるintptr_tあるいはuintptr_tがあるので、これを使うことができる。しかしながら、古い言語仕様を使うためにそれらが使えない場合は、以下のようなマクロ、あるいはtypedefを作った上でインクルードする必要があるだろう。

#ifdef __LLP64__
typedef long long INTPTR;
typedef unsigned long long UINTPTR; 
#else
typedef long INTPTR;
typedef unsigned long UINTPTR; 
#endif

上記の場合は以降の仕様に準拠させるときに問題となりうるので、やむをえない場合以外はC99/C++11の仕様に従ってintptr_tあるいはuintptr_tを使うようにしよう。

References

References
1 最も、32ビットであることを前提としていた場合問題となる
タイトルとURLをコピーしました