Visual C++のデバック編です
Visual C++のデバック機能は非常に優秀で使いこなせば
大抵のバグの箇所を発見することができます

特にC/C++言語では直接変数のアドレスを(ポインタ変数として)取り扱うことができるので
(他の言語にも参照というポインタに近い概念はある)
デバックするときは変数の値のチェックやアドレスのチェックが必須となります

まず、空のプロジェクトから
テスト用にmain.cppを作ります
デバックモードならばアドレスとかの関係も簡単に見れるので
今回はswap関数の例にしておきます

	#include <stdio.h>

	// 値入れ替え関数(駄目な例)
	void swap1(int a,int b)
	{
		int tmp = a;
		a = b;
		b = tmp;
	}

	// 値入れ替え関数(OKな例)
	void swap2(int* a,int* b)
	{
		int tmp = *a;
		*a = *b;
		*b = tmp;
	}

	int main()
	{
		int a = 5;
		int b = 10;

		printf("a = %d,b = %d\n",a,b);
		swap1(a,b);
		printf("a = %d,b = %d\n",a,b);
		swap2(&a,&b);
		printf("a = %d,b = %d\n",a,b);
	}

先に実行結果は、次のようになります
swap1関数では変数a,bの値が変わっていませんが
swap2関数では変数a,bの値が無事入れ替わっています
アドレスの概念の復習がてら、デバックで見ていきましょう

debug13.GIF

デバック起動するときは
Debugモードにしておきます
Releaseモードだと正しくデバックできません

debug.GIF

次にソースコードの左枠の部分を左クリックします
すると赤点(ブレークポイント)が打たれます
デバック起動時、このブレークポイントのところで処理が止まります

debug1.GIF

それでは、デバック起動してみます
デバック起動をするには、
デバック→デバック開始を選ぶか、もしくはF5キーを押してください

debug2.GIF

すると、赤点(ブレークポイント)を打ったところで処理が止まります(黄色い矢印)

debug3.GIF

呼び出し履歴のウィンドウはどの関数から呼ばれたかの履歴を示しています
自動変数は、今止まっている個所での変数の値をチェックすることができます

ない場合は、デバック→ウィンドウからそれぞれ出すことができます

debug4.GIF

デバックの進行方法ですが、主に次の5つです
・進行(F5キー):次のデバックポイントまで移ります
・デバックの中止(Shift + F5キー):デバックを中止します
・ステップイン(F11キー):一行進みます、関数の行の場合、関数の中身に入ります
・ステップオーバー(F10キー):一行進みます、関数の行の場合、関数の中身に入らず飛ばします
・ステップアウト(Shift + F11キー):関数の中に入っている場合、関数から抜けます

debug5.GIF

試しに、今の状態からF10キーを押します(ステップオーバー)
すると、aに5が代入され、
自動変数のaの値が5になっていることが確認できます
また、変数bが宣言されたのでbも自動変数の欄に登場します
bはまだ初期化されていないのでゴミが入っています
このように、自動変数のウィンドウは現時点で有効な変数のみを表示します

debug6.GIF

とりあえず、
swap1までF10キーを押します(ステップオーバー)

debug7.GIF

変数aとbのアドレスを見たいので
タブ切り替えでウォッチ式のウィンドウを出します
(自動変数のウィンドウでは見れない)

debug8.GIF

ウォッチ式がない場合はデバック→ウィンドウ→ウォッチ1から出せます
番号はあまり関係ありません

debug9.GIF

ウォッチ式の欄で次のように
左クリックして、入力してエンターキーを押します

debug10.GIF

bも同様に行うと、aとbのアドレスは次のようになります

debug11.GIF

この値は人によって違うと思います
私の場合は
aのアドレスは0x0012ff60
bのアドレスは0x0012ff54
になりました
このアドレスはあとでチェックするのでメモって置いてください

それではF11キーを押して(ステップイン)、swap1関数の中身に入ります
debug12.GIF

ここでいくつか見てほしい部分があります
まず、呼び出し履歴の欄です
swap1が追加されています
この下にmain関数の記述が書かれているので
このswap1はmain関数から呼び出されたものとわかります
プログラムが複雑になってきてバグが発生すると
どの関数から呼ばれてバグが発生したのか、
また、その時の変数の値などがバグの原因を突き止めるため大事になります

また、変数のアドレスを見てください
私の場合は
aのアドレスは0x0012fe7c
bのアドレスは0x0012fe80
となりましたが
先ほどのmain関数の変数a,bのアドレスと異なるはずです

試しにa,bのウォッチ式を追加します

debug14.GIF

swap1関数の変数(引数)a,bにデータは確かにそれぞれコピーされていますが
main関数の変数a,bのアドレスとswap1関数内の変数(引数)a,bのアドレスは異なるので
main関数の変数a,bに影響を与えません
つまり、swap1は無駄な処理であることがこれでわかったはずです

では、Shift+F11を押して(ステップアウト)、swap1関数を抜けましょう

debug15.GIF

デバック起動中にもブレークポイントを打つことができます
試しに、次の箇所にブレークポイントを打ってみましょう

debug16.jpg

F5を押してswap2関数に行きます
ここでswap関数には、main関数の変数aとbのアドレスを引数として渡します
さらにF5を押して、swap2関数に入ると次のようになります

debug17.GIF

ここでswap2関数のポインタ変数(引数)a,bの値にはmain関数の変数a,bのアドレスがコピーされています
確認してみてください
私の場合は
aの値は0x0012ff60
bの値は0x0012ff54
となり、main関数の変数a,bのアドレスと一致しました

やっていることはアドレスの値をコピーしているにすぎないわけです
ポインタ変数はアドレスを値として格納する変数なのでアドレスのコピーが可能になるわけです
次にウォッチ式に*a,*bの式を追加します

debug18.GIF

 *(アドレス)
は間接参照演算子とよばれ、
アドレスの指す先の値にアクセス(参照)することができます
もちろん、swap2関数のポインタ変数(引数)a,bの値はmain関数の変数a,bのアドレスそのものなので
その先の指すものは、main関数の変数a,bの値です
なのでswap2関数で*a,*bの値の入れ替えを行うことは直接main関数の変数a,bの入れ替えを行ってるのと同じです

この項目を通してデバックのやり方と、
アドレスの概念が身に着いたと思います

慣れてくるとプログラムが落ちたときなど
デバック起動でバグの原因を究明し、
バグをなくせるようになると思います
積極的に使っていきましょう

選択肢 投票
(^ω^)やったお 3  
何これwww意味不すぎwww 0  
。(`ω´#)。あぁん?最近、だらしねぇな 0  

添付ファイル: filedebug16.jpg 306件 [詳細] filedebug17.GIF 336件 [詳細] filedebug18.GIF 303件 [詳細] filedebug15.GIF 311件 [詳細] filedebug14.GIF 294件 [詳細] filedebug10.GIF 331件 [詳細] filedebug7.GIF 336件 [詳細] filedebug13.GIF 325件 [詳細] filedebug12.GIF 314件 [詳細] filedebug11.GIF 321件 [詳細] filedebug8.GIF 341件 [詳細] filedebug9.GIF 324件 [詳細] filedebug6.GIF 294件 [詳細] filedebug5.GIF 286件 [詳細] filedebug3.GIF 313件 [詳細] filedebug4.GIF 332件 [詳細] filedebug2.GIF 366件 [詳細] filedebug.GIF 325件 [詳細] filedebug1.GIF 323件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-10-19 (金) 11:06:46