コンパイラの警告レベルのあれこれ
10/31の日記でゲームがあまりできないとか言いながら、結局ロックマンロックマンを電車でプレーしていたりします(^^ゞ
そして、とてもヤヴァイ事にセーブデータが「Old Style」と「New Style」で別々になっている事に気付かず、プレーデータを上書きして、ボーゼンとしたりしている今日この頃です…orz
以前、XNAのプロジェクトが崩壊…みたいな事を書きましたが、どーにも私は引きが悪い(というかおっちょこちょいな)ので、このような情けない事になりがちです。
説明書にもう少し詳細が書いてあればなぁ~。「これは注意!」とか…
何故セーブデータが新/旧共にマージしたデータフォーマットで管理されていないのかがとても不思議です。「開発チーム内で、別行動していたのかな…?」とかとか色々と思いふけってしまいます。
そして、New Styleでプレーしていると、各ボス戦の開始の前に「Warning」という表示が出るので、こればっかり見ていたら、今回は「コンパイラの警告レベル」についてでも書いてみようかと思いました。
そして、とてもヤヴァイ事にセーブデータが「Old Style」と「New Style」で別々になっている事に気付かず、プレーデータを上書きして、ボーゼンとしたりしている今日この頃です…orz
以前、XNAのプロジェクトが崩壊…みたいな事を書きましたが、どーにも私は引きが悪い(というかおっちょこちょいな)ので、このような情けない事になりがちです。
説明書にもう少し詳細が書いてあればなぁ~。「これは注意!」とか…
何故セーブデータが新/旧共にマージしたデータフォーマットで管理されていないのかがとても不思議です。「開発チーム内で、別行動していたのかな…?」とかとか色々と思いふけってしまいます。
そして、New Styleでプレーしていると、各ボス戦の開始の前に「Warning」という表示が出るので、こればっかり見ていたら、今回は「コンパイラの警告レベル」についてでも書いてみようかと思いました。
私はC言語でプロジェクトを作成する時の設定の中の一つに「警告レベルを最大にする」という習慣があります。
これは「些細な事でもいいから、コンパイラがおかしいと思ったら、教えてください。」という意味に当り、警告をできるだけ潰して行く事に美学を持っています。
Visual C++の場合に限った話ですが、1.0の時代からプロジェクトのデフォルト警告は最大には設定されておらず、現在の2008(9.0)においてもこれは変っていません(デフォルトの警告は3{/W3}です)。
私は「意図しない警告がある以上は、そのプロジェクト(のソース)は、何か不都合があっても、全て自分(テメエ)の責任である。」という考えがあるため、警告レベルを最大にしてこのメッセージが出ない所まで追求します。「そうしないと気持ち悪い」とまで感じたりする程だったりします。
大抵この手の警告が表示される個所というのは、
【よく見かけるもの】
・関数の未使用引数や、関数内で使用しない変数に対する警告。
・符号を無視した代入による警告。
・符号を無視した比較による警告。
・データ型の領域を無視した代入による警告(intとboolの使い分けがいい加減の場合とか)。
【たまに見かけるもの】
・マクロの再定義
・非標準の呼び出し(コンパイラのバージョンが変ると出やすい)
という感じなので、「よく見かけるもの」は、バシバシ出ないように潰していきます。
(関係ないですが、この"バシバシっ"て、"バシシ"っぽいですねw)
特に符号の無視はfor文等でかなりマズイ事になりやすいので、注意が必要だったりします。
一つ例を挙げてみると…
この関数は「startからendの回数処理を行う」というものですが、引数がint(符号あり)となっており、関数内部のループカウンタがsize_t(符号なし)となっています。
もしもこの関数を
という感じで呼び出した場合、一見するとcall.1が10回、call.2が11回処理されそうに思えますが、実際にはcall.2では0回になります。
intで考えると-1~10は、10-(-1)=11回ですが、関数中のループがsize_tになっているため、32bitコンパイラのsize_tであれば、大抵「"size_t i = start"のiは4294967295」という数字になります。これにより、startが-1ではなくなるので、endの値よりも大きいという事で、ループ処理が行われずに関数を抜けるという事になります。
VC++においてプロジェクトの新規作成にて作成したデフォルトのプロジェクトの警告設定であれば警告が出ますが、gcc等でmakeファイルの設定等をミスると、これに気付かず「あれ?何がおかしいのだろう…」という感じになるかもしれません。
このように警告はできるだけ出してもらい、且つできるだけ意味を理解して潰して行きたいところです。
また、昔(VC++ 6.0の頃)は、STLを使用するだけで警告が大量に出ていたので、とても難儀ではありましたが、最近はこの事情がやっと減りました。
しかし、STLのコンテナをtypedefでネストすると、コンパイラの解析バッファが不足するという事は現時点でも解決されていないので、別段こちらは悪くなくとも警告が出るので、「#pragma warning(disable:xxxx)」で黙らせるようにしています。これは主にstd::mapの中に、更にtypedefしたmapを…のようなネストをtypedefすると発生しがちで、VC++2005辺りでは、警告4503で見掛けたりします。
(Boostとか使う人なら、まずやらないとキツそうですね。ゲーム開発ではオクトツリーのようなデータの持ち方をすると発生したりして(^^;)
そしてご存知の方もいると思いますが、VC++2005以降からはCRTのセキュリティ強化に伴い、例えばsprintf関数一つ取っても「この関数は古いインターフェース」とされてきているので、sprintf_s関数を呼び出さなければなりません(正確にはC99からですかね)。私の場合はこれの潰し方はケースバイケースで、#pragma(もしくは#defineでセキュリティを抑止)で撃墜するか、新しい仕様に合せてsprintf_sのように真面目に実装するかは、そのプロジェクト(お客様)次第という感じやっています。
…が、個人的には「#pragama warning(disable:xxxx)」という物は、
「それは分っているけど、今は目を瞑ってね♥」
なので、「#pragmaで逃げるのは、漢(おとこ)らしくない!」という感じに思っています。
ゲーム開発にてこの例(sprintf)を使うとしたらメッセージ表示関連位しかパッと思いつきませんが、バッファオーバーランを引き起す関数には全てこのインターフェースが適用されているので、何気に「あっ!こんな所でっ!」という警告を食らいそうな気はします。
警告… できるだけ見たくないものです。(^^ゞ
これは「些細な事でもいいから、コンパイラがおかしいと思ったら、教えてください。」という意味に当り、警告をできるだけ潰して行く事に美学を持っています。
Visual C++の場合に限った話ですが、1.0の時代からプロジェクトのデフォルト警告は最大には設定されておらず、現在の2008(9.0)においてもこれは変っていません(デフォルトの警告は3{/W3}です)。
私は「意図しない警告がある以上は、そのプロジェクト(のソース)は、何か不都合があっても、全て自分(テメエ)の責任である。」という考えがあるため、警告レベルを最大にしてこのメッセージが出ない所まで追求します。「そうしないと気持ち悪い」とまで感じたりする程だったりします。
大抵この手の警告が表示される個所というのは、
【よく見かけるもの】
・関数の未使用引数や、関数内で使用しない変数に対する警告。
・符号を無視した代入による警告。
・符号を無視した比較による警告。
・データ型の領域を無視した代入による警告(intとboolの使い分けがいい加減の場合とか)。
【たまに見かけるもの】
・マクロの再定義
・非標準の呼び出し(コンパイラのバージョンが変ると出やすい)
という感じなので、「よく見かけるもの」は、バシバシ出ないように潰していきます。
(関係ないですが、この"バシバシっ"て、"バシシ"っぽいですねw)
特に符号の無視はfor文等でかなりマズイ事になりやすいので、注意が必要だったりします。
一つ例を挙げてみると…
// startからendの回数処理を行う void hoge(int start, int end) { for(size_t i = start; i < end; i++) { // 何か処理を… } } |
この関数は「startからendの回数処理を行う」というものですが、引数がint(符号あり)となっており、関数内部のループカウンタがsize_t(符号なし)となっています。
もしもこの関数を
// call.1 hoge(0, 10); // call.2 hoge(-1, 10); |
という感じで呼び出した場合、一見するとcall.1が10回、call.2が11回処理されそうに思えますが、実際にはcall.2では0回になります。
intで考えると-1~10は、10-(-1)=11回ですが、関数中のループがsize_tになっているため、32bitコンパイラのsize_tであれば、大抵「"size_t i = start"のiは4294967295」という数字になります。これにより、startが-1ではなくなるので、endの値よりも大きいという事で、ループ処理が行われずに関数を抜けるという事になります。
VC++においてプロジェクトの新規作成にて作成したデフォルトのプロジェクトの警告設定であれば警告が出ますが、gcc等でmakeファイルの設定等をミスると、これに気付かず「あれ?何がおかしいのだろう…」という感じになるかもしれません。
このように警告はできるだけ出してもらい、且つできるだけ意味を理解して潰して行きたいところです。
また、昔(VC++ 6.0の頃)は、STLを使用するだけで警告が大量に出ていたので、とても難儀ではありましたが、最近はこの事情がやっと減りました。
しかし、STLのコンテナをtypedefでネストすると、コンパイラの解析バッファが不足するという事は現時点でも解決されていないので、別段こちらは悪くなくとも警告が出るので、「#pragma warning(disable:xxxx)」で黙らせるようにしています。これは主にstd::mapの中に、更にtypedefしたmapを…のようなネストをtypedefすると発生しがちで、VC++2005辺りでは、警告4503で見掛けたりします。
(Boostとか使う人なら、まずやらないとキツそうですね。ゲーム開発ではオクトツリーのようなデータの持ち方をすると発生したりして(^^;)
そしてご存知の方もいると思いますが、VC++2005以降からはCRTのセキュリティ強化に伴い、例えばsprintf関数一つ取っても「この関数は古いインターフェース」とされてきているので、sprintf_s関数を呼び出さなければなりません(正確にはC99からですかね)。私の場合はこれの潰し方はケースバイケースで、#pragma(もしくは#defineでセキュリティを抑止)で撃墜するか、新しい仕様に合せてsprintf_sのように真面目に実装するかは、そのプロジェクト(お客様)次第という感じやっています。
…が、個人的には「#pragama warning(disable:xxxx)」という物は、
「それは分っているけど、今は目を瞑ってね♥」
なので、「#pragmaで逃げるのは、漢(おとこ)らしくない!」という感じに思っています。
ゲーム開発にてこの例(sprintf)を使うとしたらメッセージ表示関連位しかパッと思いつきませんが、バッファオーバーランを引き起す関数には全てこのインターフェースが適用されているので、何気に「あっ!こんな所でっ!」という警告を食らいそうな気はします。
警告… できるだけ見たくないものです。(^^ゞ
コメント
コメントの投稿
« 昔のゲームの想い出 [0080] 「ガズラー」 [テーカン] [1983] [アーケード] l Home l サイクロプスのモデルを作り変え »