全てのCプログラマが未定義な振る舞いについて知っておくべきこと

全てのCプログラマが未定義な振る舞いについて知っておくべきこと #1/3

あまりにも「あるあるwww」過ぎて凄く読み応えのある記事.ゲームプログラムは特に速度を優先するために安全性を犠牲にすることがありますが,その結果バグを引き起こしやすいという側面もあります.

未初期化変数の使用

たぶんゲームプログラムにおいて最も多いと言われているバグ発生原因.特にVector系やMatrix系の演算では速度を重視するためにわざと初期化を行っていないという事はよくあります.特にC言語で書かれたコードの場合はスコープ内の最初でしか宣言できないという事もあって,よく変数を使いまわすという暴挙も行われていたりします.一度初期化したはいいものの,再使用時には正しく初期化されずに使用される事により未定義動作を引き起こす事もあります.

大きすぎるシフト

ゲームプログラムではよくメモリを節約するために一つの変数に様々な情報を詰め込み,それをビットシフトする事によって動作するプログラムがよく書かれます.よくあるのはcolorという変数にRGBAを全部詰め込み,ビットマスクもしくはビットシフトで計算を行うというケースです.この計算は1bitでもミスするとトンデモない事がよく起きるので基本的には使わない,もしくは完全にラップされた処理のみで使うようにしましょう.

不正なポインタのデリファレンスと配列の範囲外アクセス

はい,きたー C言語orC++で書かれている限り起こり得る最も危険なプログラムです.この現象により起こるバグがよくある再現不可な類のバグになる.そしてよく分からないけど何かおかしい,全く検討もつかないそういう類のバグが起きる狂気の存在です.C言語はともかく,C++ではこれらを予防する仕組みも沢山あるので積極的にそういうものを利用するようにしましょう.

NULLポインタのデリファレンス

動作としては未定義ですが,大抵の処理系では停止します.もちろん,ポインタにアクセスする際にはNULLポインタチェックは必要となりますが,上手く設計されているコードでは殆ど要らないはずです.一番いいのはポインタを扱うコードを極力減らす事です.C言語ではポインタは必須ですが,少なくする事は可能です.C++においては参照やもっと安全に使用出来るスマートポインタがあります.とにかくポインタを使わせないコードを書かせる事が大切です.

型に関するルール違反

世の中には当たり前のようにキャストを使いまくる人がいますが,そのコストは0ではありませんし,当然キャストの結果次第ではプログラムは死にます.簡単に.特にint⇔floatの変換やポインタのキャストは危険性が高く,バグの温床となる原因です.C++ではこれを厳密にチェックする機構がありますので,それによりバグを減らす事は出来ます.が,依然としてキャスト大好きっ子は減らないのでまずはキャストさせないプログラムを書けないか?と考える事は非常に重要です.



この他にもコンパイラの最適化やコンパイラ特有のバグがあったりして,C言語orC++は簡単にバグが作れます.かと言ってそれを防ぐ手立てがないわけでなく,ちゃんとした知識さえあればとんでもない事態にはなりにくいはずです.特にゲームプログラムは速度優先だからという言い訳をせず,安全性を常に意識しながら高速化をしたいです.個人的には高速化するならアルゴリズムから見直せと言いたいと思うことばかり.