ポインターのアドレスを整数型にキャストするときは要注意

C言語及びC++ではポインターと呼ばれる、そのメモリー領域のアドレスの場所を指し示す特有の機能があるが、それの計算等を行う際に往々にしてキャストが行われるが、その際に環境依存の問題を引き起こす危険性がある。これから述べたいのは、私が見たことのある例で、普通であれば絶対に問題を引き起こすものである。

今回、私が遭遇したものは、以下のようなコードのものである。

上記のコードでは、ポインターの計算こそ行っていないものの、環境によってはバグに悩まされるコードの例である。

というのは、void *ptr = getptr();で取得したアドレスの値、及びそれを格納するサイズは環境によって変わるからである。例えば、一般的な32bit環境では32bit型として扱われるため、このままでも基本的には問題はない1 のだが、64bit環境では多くの場合バグが発生する危険性が高い。

これは、64bit環境では、ポインターのアドレス値が64bitで扱われる一方、多くのシステムではint/unsigned int型が32bit型のままであることで、キャストの際に値の一部が消失してしまうことがあることが原因である。

これを防ぐには、適切な型に切り替える必要がある。C99以降及びC++11以降では以下のような書き方ができる。

こうすることによって、ポインターのサイズが扱える値が使えるため、問題が発生することが基本的になくなる。万一比較的古い仕様のC言語を使う場合でも、適切に#ifdef〜#endif及びtypedefを駆使することでほぼ同様のことは行える。

C言語においてはこのように他の言語にはない落とし穴があるので、是非とも気をつけてほしい。

ウェブマスター。本ブログでITを中心にいろいろな情報や意見などを提供しています。ご用の方はコメントかコンタクトフォームにて。
  1. WindowsやUNIX系OS、GNU/Linuxシステムなど、一般的な32bitアーキテクチャーで採用されているILP32の場合は問題ない。LP32ではunsigned intは16bit型の為、バグが発生する []
スポンサーリンク

フォローする