Version 6.18
デバッグビルドとリリースビルド再び
「さて今回は、デバッグする上で重要なことのひとつ、デバッグビルドとリ
リースビルドってものについて解説します」
『って、前にそれ教えてもらったよ?』
「 Ver 3.24 ( No.049 ) 」だね。でもちょっとだけだったでしょ」
『最後の4分の1だけ……』
「というわけで、もう少し突っ込んで見てみましょう。もちろんデバッグに
も関係あるしね」
『そりゃデバッグモードってゆーんだもんね。でも具体的にゆーと?』
「まず、一番重要なのは ASSERT() や TRACE() かな。っと、まず #ifdef
とか思い出して」
『 Ver 6.06 ( No.106 ) とか Ver 6.07 ( No.107 ) だね』
「そのとき<条件コンパイル>ってやったでしょ。実は ASSERT() や
TRACE() にはこの条件コンパイルが大きく関わってくるんです」
『何を #define するかでプログラムが変わってくるってヤツね。 ASSERT()
とかが変わる?』
「変わるんです。と、その前にちょっと復習」
void CDebugDlg::OnButton1()
{
int i = 100;
CString cStr;
cStr.Format( "%d", i );
MessageBox( cStr );
// 100
}
『えーっと、確か CString::Format() って TRACE() みたく、数字を
CString に入れてくれるんだよね』
「そう。最後はダイアログとしてそれを表示」
『うん、 100 って出た。でもなんで TRACE() 使わないの?』
「それがミソ。でもその前に、 ASSERT() の方。今度はこれ試して」
void CDebugDlg::OnButton1()
{
int i = 100;
ASSERT( ++i );
CString cStr;
cStr.Format( "%d", i );
MessageBox( cStr );
// 101
}
『さっきのと違うとこ…… ASERT() で i を 1 増やしてるね。でもそれだ
けだし結果も当たり前の 101 ……』
「うん、これはその確認。じゃ、今度はリリースビルドで試してみましょ
う。やり方憶えてる?」
『教えてもらった?』
「えーっと……あ、 Ver 3.24 ( No.049 ) で」
『ホントだ。えっと、【ビルド】−【アクティブな構成の設定】、んで
Release 、でいいんだよね』
「そうそう。それでビルドして実行してみて」
『ほいビルド……そういえば、なんでこれ、時間掛かるの? デバッグの時
も、最初にビルドした時って時間掛かるし』
「普段時間掛からないのは、前にビルドした時から変更されたとこだけビル
ドするから」
『あ、だから2度目からは時間掛からないんだ』
「大きく書き変えたりしたら、やっぱり全部ビルドし直して時間かかるよ」
『へー。あ、終わった。んで実行。あ』
「〈デバッグ情報がありません〉ダイアログは無視していいよ」
『ほい。と、さっきみたく普通にボタン押して……あ! 100 だ、ダイア
ログに 100 ってなってる!』
「そう、増えてないでしょ。つまりリリースビルドだと」
ASSERT( ++i );
「の1行が丸ごとなくなっちゃうわけ」
『なんてこったい……』
「これが、前回言った〈リリースビルドだと ASSERT() が働かない〉ってこ
と」
『へぇ……あ、ちょっと試していい?』
「もちろん」
void CDebugDlg::OnButton1()
{
ASSERT( 0 );
}
『うわー、リリースビルドだと止まらないしダイアログも出ない……』
「でしょう。じゃ、なんでそうなるか見てみましょう。 MFC のインクルー
ドファイルの中に Afx.h ってファイルがあるから、その中から ASSERT()
を探して」
『あ、結構上の方にあった……けど、ふたつあるよ、どっちが本物?』
「両方とも本物。上から見てくと……」
// Afx.h
#ifdef _DEBUG
// 略。
#define ASSERT(f) \
// 略。
#else // _DEBUG
#define ASSERT(f) ((void)0)
// 略。
#endif // !_DEBUG
『??……あ! そっか、これが条件コンパイルのとこなんだ』
「そゆこと。 _DEBUG が #define されてると上の ASSERT() 」
『そうじゃない時は下の ASSERT() 。って、上はなんか色々入ってるのに、
下はなんかすんごくちょっとなんですけど』
「っていうか、つまり ASSERT(f) が ((void)0) になるわけでしょ?
ASSERT(f) の f は?」
『ないね……そっか、これが ++i が消えちゃう原因?』
「そゆこと! つまり ASSERT() が中身もまるごと ((void)0) になっちゃ
うってこと」
『……ねー』
void CDebugDlg::OnButton1()
{
((void)0);
}
『ってなんか変だけど。ただの空白ってダメなの?』
「そうだねー、もし ASSERT() が空白になると」
CString cStr ASSERT( 0 );
「ってできちゃうんだよね」
『うわ変……』
「だから空白じゃなくて 0 にして、でもそれだけだと」
int i = ASSERT( 0 );
『うわまた変……』
「で、代入できないように void にキャストするわけ」
『 void って、関数の戻り値ないときのだよね』
「そう、だから何にも代入できないわけ」
『……んー、まとめると、ようするに変なことできないようにってこと?』
「そういうこと。まぁちょっとしたテクニックみたいなものだけどね」
『なんかちょっと奥が深いかもしんない……。って話を戻して、つまり
_DEBUG ってのが #define されてるかどうかなんだよね』
「そうそう。実はそれ、もう見てるんだよ」
『見てる?』
「 Ver 6.07 ( No.107 ) 見て」
『あ、【プロジェクトの設定】で #define されてるんだ!』
「で、それされてるのがデバッグビルドの方。リリースビルドだと」
『ないね。そうなると ASSERT() まるごと消えちゃうんだ』
「そういうこと。たとえばリリースビルドで _DEBUG, を加えると」
『おおっ、今度はちゃんと 101 になった!』
「ちなみにデバッグモードで _DEBUG, を取り除くと」
『おおっ、 101 ……ってさっきと変わらないやん』
「ちょっと複雑な話になるけど、【プロジェクトの設定】の
【C/C++】−【コード生成】ページの【使用するランタイム ライブラリ】で
(デバッグ)って付いてるのを選んでると、無理矢理 _DEBUG が #define さ
れちゃうから。だからこれを【マルチスレッド(デバッグ)】にすると」
『お、今度はちゃんと 100 になった。こうすれば ASSERT() がなくなっ
ちゃうわけね』
「ちなみになくならないのもあるよ。さっきの ASSERT() とかがあったとこ
に VERIFY() ってあるでしょ」
『うんある。あ、これは ((void)(f)) に置き換わるね。 f があるから、
こっちは ++i がなくなんないんだ』
「だから、 ASSERT() の中が消えてほしくない場合は VERIFY() を使うって
手もあるかな。でも」
『でも?』
「僕はあんまり使わないかなぁ。 ASSERT() と VERIFY() をごちゃごちゃに
するのはね。別に無理矢理中に消えて欲しくないコード書くこともないし」
『前に、1行に詰め込まない方がいいって言ってたもんね』
「ま、便利な面もあるから使うのも悪くないけど。たとえば関数の戻り値を
ASSERT() でチェックしたい時とか」
『そっか、そういうとき2行にすると、戻り値を入れる変数作んなきゃいけ
ないんだね』
「その辺は人それぞれ、かな。あとこの系統の最後に TRACE() 」
『いつものおなじみの TRACE() も、デバッグの時はなくなっちゃうんだ』
「ただ重要なのは、 TRACE() はなくなっちゃうけど、アウトプットウィン
ドウに出力する機能がなくなっちゃうわけじゃないってこと」
『どゆこと?』
「実は TRACE() は、 API の OutputDebugString() の機能を使ってるんで
す。だから」
void CDebugDlg::OnButton1()
{
OutputDebugString( "あうとぷっと\n" );
}
『うりゃ、ホントだアウトプットに出た』
「で、これはリリースモードでもちゃんと出るから」
『ほい。あ、ホントに出た』
「つまり!」
『つまり?』
「デバッグビルドとかリリースビルドって言っても、こういう仕組みでなっ
てるから、たとえばリリースビルドでもある程度デバッグしたりはできるん
だよね」
『この OutputDebugString() とか、さっきの _DEBUG とか?』
「そゆこと。今はまだちょっと難しくても、こういうことを知っていれば、
あとで〈リリースビルドでデバッグしないと!〉って時でも」
『できるようになる?』
「なる!」
/*
Preview Next Story!
*/
『で、それっていつのこと?』
「〈これっていつまで続くの?〉ネタはつまらないからやめない?」
『やめない。っつーか今回も長すぎでしょ』
「デバッグ編だけでこんなになるとはなー」
『なんで長くなるの?』
「教えたいことばかりだから」
『というわけで次回』
< Version 6.19 デバッグウィンドウがいっぱい >
「につづく!」
『そんなにプログラミングって大変なものなの?』
「……世の中って汚いよね……」
『答えになってなーい!』