Version 6.19
デバッグウィンドウがいっぱい
「さて、いきなりですがデバッグ編は今回で最終回です」
『いきなり!』
「でもはしょった部分はほとんどないから」
『そりゃそんだけ伸びればねぇ……』
「これまではプログラム上でのバグの捕まえ方について解説してきました」
『プリプロセッサとか、それ関係のコンパイルエラーのとか、あとバグを見
つけるための、コンパイルエラーにする方法とか ASSERT() とか』
「そういえば演算子とかもやったね。だからこんなに膨らんだのかも」
『で、今回まででそういうのは全部教わったってことね』
「後回しにしたとこ以外はね」
『それ、教わったって言わない』
「まぁそうだけど……予備知識を教えたらそれから教えるから。さて今回は
デバッグウィンドウについて」
『デバッグウィンドウ?』
「そう。まずはこれ」
void CDebugDlg::OnButton1()
{
int i = 100;
TRACE( "%d\n", i ); // ここにブレークポイント。
}
『ブレークポイントをセットして、実行して、止まったよ?』
「まず、デバッグウィンドウは〈ブレークポイントで止めた時に使うもの〉
ってことを憶えておいて」
『実行して、一時停止してるとこってことね』
「そう、それ重要。デバッグウィンドウは〈今実行してる状態〉を表示する
ものだから、実行中じゃないと意味ないわけ」
『実行してる状態って、たとえばメモリとか?』
「そう! Ver 4.02 ( No.052 ) のポインタの解説で使った【メモリ】
ウィンドウもデバッグウィンドウのひとつ」
『デバッグウィンドウだと、メモリぢかに見られるんだよね。アドレス指定
して。確かにこれは実行中じゃないとね』
「メモリウィンドウの見方は、その回に教えたからいいよね」
『たとえば &i を TRACE() したりしてアドレス見て、それを打ち込めば、
16進表示でメモリ見られる、だよね』
「そうそう。ただ、メモリを直に見るだけだと分かりにくいとこがあるか
ら、それをもう少し解りやすくするのが【ウォッチ】。【表示】−
【デバッグ ウィンドウ】−【ウォッチ】を開いて」
『ってゆーか、ここにあるのがそのデバッグウィンドウを開くのなんで
しょ? メモリもあるし』
「そうそう。今回はここにあるのを見ていくから。で、ウォッチは特定の変
数の値を調べます。ソースコードの」
int i = 100;
「の i を、このウォッチにドラッグ&ドロップして」
『ほい。あ、 i が入って 0x00000064 って出た』
「右クリックして【16進表示】をオフにしてみて」
『 100 になった。あ、今 i に 100 が入ってるから!』
「そゆこと。こうやって i の中身を見られるんです。さらに、その 100 を
クリックして 101 にしてリターンして、【中カッコを飛び越える】ボタン
で1行進めてみて」
『……そんなことしていいの?』
「大丈夫だから」
『うーん……うわ、なんか出た!』
コンパイル中...
DebugDlg.cpp
コードの変更を適用しています...
エディット・コンティニュー - エラー 0 ,警告 0
『な、何これ?』
「デバッグ中に、今 100 を 101 に変えたとこをコンパイルし直したんだ
よ」
『そんなことできんの?』
「ってゆーかできてるし。もちろん、まだデバッグ中。アウトプットの表示
が今ので【ビルド】になってるから、【デバッグ】に戻して」
『うん……あ、 101 って出てる!!』
「つまり i の中身をその場で 100 から 101 に変えたわけ」
『すご……こんなことできるんだ』
「ま、とんでもない変更はできないけどね。でも実際にはこのウォッチは使
わないかな」
『なんで?』
「他に便利なのがあるから。同じく【変数】ウィンドウを開いて」
『さっきと同じメニューのだよね。あ、前に見たことあるかも』
「変数ウィンドウには、その場で使える変数全部載ってるから、ウォッチ
ウィンドウみたいにドラッグ&ドロップしなくていいんだよね」
『それは楽かも。【自動】【ローカル】【this】ってあるけどこれは?』
「【自動】はその場で見たそうなのを適当に見繕って。特に、この【自動】
には関数の戻り値が表示されたりするから便利かも」
『ホントだ、【 AfxTrace 戻り値】ってある。でも AfxTrace() って?』
「 TRACE() が呼んでる関数のこと。そこからさらに OutputDebugString()
が呼ばれてるから」
『それ知らないとわんないじゃん……』
「そうかも……。【ローカル】はローカル変数ね」
『今は i だけだから i だけ……と思ったら this なんてのも』
「その this と【this】のとは中身同じだから。【this】って憶えてる?」
『何だっけ……』
「 Ver 5.25 ( No.090 ) でちょっとだけやったけど難しいからね……。
えっと、 CDebugDlg::OnButton1() メンバ関数はもちろん CDebugDlg の変
数のメンバ関数として呼ばれてるでしょ」
『思い出した! その変数のポインタなんだよね、 this って』
「その通り! 具体的に言うと、 CDebugApp::InitInstance() で」
CDebugDlg dlg;
「で作ってる変数のアドレスが、この CDebugDlg::OnButton1() での this
ポインタ」
『で、それの変数が見えるって……あ、メンバ変数が見えるんだ!』
「そゆこと。 Ver 6.16 ( No.116 ) で作った m_i もあるでしょ」
『へー。こうやって分けて見られるんだ』
「それでもメンバ変数とかは多過ぎて見にくいこともあるから、そういう時
はさっきのウォッチ使った方がいいかも」
『この変数ウィンドウでも、変数の中身変えたりできる?』
「もちろんできるよ。では次、【コールスタック】」
『ほい』
CDebugDlg::OnButton1() line 181
_AfxDispatchCmdMsg(CCmdTarget * 0x0064fce8 // 略。
CCmdTarget::OnCmdMsg(unsigned int 0x000003e8 // 略。
CDialog::OnCmdMsg(unsigned int 0x000003e8 // 略。
// 以下略。
『かなりよく分からない……あ、でも CDebugDlg::OnButton1() は分かる
よ。それに line 181 って、今止まってる行だし』
「このコールスタックは、今呼ばれてる関数が、どういう関数をたどってき
たかを表示してくれるもの」
『ってことはつまり、 CDialog::OnCmdMsg() が CCmdTarget::OnCmdMsg()
を呼んで、それが _AfxDispatchCmdMsg() を呼んで、さらにそれが
CDebugDlg::OnButton1() を呼んで今に至る、ってこと?』
「そういうこと! ダブルクリックすると、その関数のとこに飛ぶから」
『はー、 CDebugDlg::OnButton1() だけでこれだけ複雑に呼ばれてるの
ねー』
「このコールスタックウィンドウは、たとえば ASSERT() した時ってその
ASSERT() 呼んでる部分に飛ぶでしょ」
『そこでこれを見れば、どういうふうにそこに来たか判るんだ!』
「まーそれくらいしか使い道ないけどね。ちなみにコールは〈呼ぶ〉、ス
タックは〈積む〉って意味だから」
『関数が積み上げられてく、ってわけね』
「さて、次は【レジスタ】」
『ほい。……ぜんっぜんわかんないんですけど』
「だね。レジスタっていうのは CPU の中に置いてある、ちっちゃなメモリ
領域。メモリって言うのはまずいかな?」
『つまり普通のメモリとは違うってこと?』
「そういうことになるかな。 CPU が計算する時ってメモリを使うわけじゃ
なくて、メモリからレジスタに移してからするんです。これはそのレジスタ
の中身が見られるの」
『むつかしいね……』
「これは僕も分かんないけどね。これは普通のプログラムでは重要じゃない
かな。あとちょっと Ver 6.08 ( No.108 ) を見て」
『んーっと……あ、似たようなの書いてあるとこがある。 EAX とか。こ
れって、落ちた時のダイアログに出るのだね』
「そう。ま、ここではそのダイアログに出てたのが、このレジスタの中身
だってことくらいで。最後は混合モード」
『これ、この前見たね』
「あ、さっきの Ver 6.08 ( No.108 ) だ。そのときちょっと言ったけど、
混合モードはコンパイルする前のプログラムとした後のプログラムを照らし
合わせて表示するもの」
『でも相変わらず分かんないけど……』
「これも上級者向け、滅多に使わないかな。ちなみにここに書かれてるのは
【アセンブラ】って言語のプログラム」
『あせんぶら? また違う言語なの?』
「んー、なんて言うかな、コンパイルした後のプログラムはこのアセンブラ
って言語でも書ける、ってとこかな」
『なんか回りくどい言い方』
「そうだね……まー難しいからそれはもーっとあとで」
『はいはい』
「で、ここで重要なことは、こういうふうにコンパイル前と後が結び付けら
れるのは、デバッグビルドだから」
『なんかまたデバッグビルドの設定でそういうのが変わってくる?』
「【プロジェクトの設定】のいくつかの設定を変えないと、この結び付ける
情報が加えられないわけ」
『継ながらないと?』
「ブレークポイントとか使えない!」
『げ、そうなの?』
「だから今回のデバッグウィンドウは全部使えないし、ステップインとかも
できないわけ。ま、逆に言うと、リリースビルドでもこの設定をデバッグビ
ルドのに変えればそういうデバッグできるんだけどね」
『質問! 具体的にそれどうすればいいの?』
「いっぱいあるかな……【プロジェクトの設定】の、【C/C++】−【一般】
の【最適化】を【デフォルト】に、同じく【デバッグ情報】を【エディット
コンティニュー用のプログラムデータベース】にして、あと【リンク】−
【デバッグ】の【デバッグ情報】をオンにすればOK」
『ふっ複雑!』
「確かにね」
『もひとつ質問! ……結局それって、リリースビルドの設定を、デバッグ
ビルドの設定に同じにしてるんだよね』
「うん」
『……だったらリリースビルドとかデバッグビルドとか関係ないじゃん』
「だね」
『だねって……』
「そう、実はデバッグビルドとリリースビルドって、プロジェクト作った時
にデフォルトの2設定ってだけで、基本的な違いはないわけ。メニューの
【ビルド】−【構成】でこの設定を増やしたり減らしたりできるし」
『つまり最初からあるデバッグビルドとかリリースビルドとかって気にしな
くていいわけね』
「そゆこと。も少し色々分かってきたら細かく設定することになると思うか
ら、そうなると」
『デバッグビルドとリリースビルドの中間とか?』
「ま、そういうの作る時は、バグが見つからなくて四苦八苦してるときだろ
うけど……」
『げー』
/*
Preview Next Story!
*/
『デバッグ編終了! って、次もまだ Version 6 のままだよ?』
「次回はちょっと番外編」
『……そんなんやってる暇あるの?』
「もういいじゃんこの際。それに、それなりに有用かもしれないし」
『有用ねー』
「というわけで次回」
< Version 6.20 水希流コーディング&デバッグ術 >
『につづく、ってなにそれーっ!!』
「たぶん有用」