この記事では、Visual Studio の基本的なデバッグのヒントのみを取り上げますが、同様に役立つ他のヒントもあります。 Visual Studio (少なくとも VS 2008 の下) でのネイティブ開発のためのデバッグのヒントをいくつかまとめました。 (マネージド コードで作業している場合、デバッガにはさらに多くの機能があり、CodeProject にそれらの機能を紹介する記事があります。) 以下に、私がまとめたいくつかのヒントを示します。 Windows
範囲外のシンボルの後のヒープオブジェクトを表示する
配列の値を表示する
不必要な関数の入力を避ける
出力ウィンドウに出力する
メモリリークを分離する
リリースビルドをデバッグする
リモート デバッグ
ヒント 1: 例外割り込み
ハンドラーを呼び出す前に、例外発生時にデバッガーを起動して割り込みを行うことができ、例外発生直後にプログラムをデバッグできます。コールスタックを操作すると、例外の根本原因を見つけることができます。
Visual Studio では、中断する例外の種類または特別な例外を指定できます。 [デバッグ] > [例外] を選択すると、ダイアログ ボックスが表示されます。デバッガに付属するデフォルトの例外に加えて、独自のカスタム例外を追加することもできます。
ウォッチ ウィンドウまたはクイックウォッチ ダイアログ ボックスには、擬似変数と呼ばれるいくつかの特定の (デバッガーが認識可能な) 変数が用意されています。ドキュメントには次の内容が含まれます:
$tid—現在のスレッドのスレッドID
$pid—プロセスID
$cmdline—プログラムを開始するコマンドライン文字列
$user—実行中のプログラムのアカウント情報
$ registername——–レジスタ registername の内容を表示します。
いずれの場合でも、最後のエラーに関する疑似変数は非常に便利です:
$err——–最後のエラーのエラー コードを表示します。
$err,hr—最後のエラーを表示します。 error エラー メッセージ
デバッグ シンボルが境界を越えた後でも、オブジェクトの値を確認したい場合があります。このとき、ウォッチ ウィンドウは無効になり、オブジェクトはまだ存在しますが、再度表示することはできません (また更新することもできません)。オブジェクトのアドレスがわかっていれば、引き続きそのオブジェクトを完全に観察できます。アドレスをこのオブジェクト タイプのポインタに変換し、ウォッチ ウィンドウに配置できます。
以下の例では、do_foo() からステップアウトした後、_foo にアクセスできなくなります。ただし、アドレスを foo* に変換した後は、このオブジェクトを引き続き観察できます。
大きな配列を操作している場合 (少なくとも数百の要素を想定しますが、おそらくそれより少ないと想定します)、ウォッチ ウィンドウで配列を展開し、いくつかの要素を探します範囲内の特定の要素をスクロールし続ける必要があるため、配列がヒープ上に割り当てられている場合は、ウォッチ ウィンドウで配列要素を展開することもできません。これには回避策があります。 (array+
MFC を使用していて、その中で CArray、CDWordArray、CStringArray などの「配列」コンテナーを使用している場合。もちろん、同じフィルタリング方法を使用することもできます。さらに、データを保持する実際のキャッシュである配列の m_pData メンバーを確認する必要があります。
ヒント 5: 不要な関数の入力を避ける
コードをデバッグするとき、コンストラクター、代入演算など、スキップしたい関数を入力することがよくあります。私が最も気になるのは CString コンストラクターです。以下は例です。 take_a_string() 関数に入る準備ができたら、まず CString コンストラクターを入力します。
void take_a_string(CString const &text){}void test_string(){ take_a_string(_T("sample"));}
幸いなことに、どのメソッド、クラス、または名前空間全体をスキップするかをデバッガーに指示できます。これを行う方法も変更され、VS6 の時代に戻ると、通常は autoexp.dat ファイルを介して指定されていました。 Visual Studio 2002 は、レジストリ設定を使用するように変更されました。一部の機能をスキップするには、レジストリにいくつかの値を追加する必要があります (詳細は以下を参照):
実際の場所は、使用している Visual Studio のバージョンとオペレーティング システム プラットフォーム (x86 または x64、レジストリは次のとおりです) によって異なります。 Windows の 64 ビット ブラウズでのみ使用されます) 値の名前は、ルールの優先順位を表す数値であり、数値が大きいほど優先順位が高くなります。値データは、フィルタリングおよび実行方法を指定する正規表現の REG_SZ 値です。
CString メソッドの入力を避けるために、次のルールを追加しました:
これにより、上記の例で take_a_string() を強制的に入力しても、デバッガーは CString のコンストラクターをスキップします。
ヒント 6: コードからデバッガーを起動する
プログラムにデバッガーをアタッチする必要が生じることはほとんどないかもしれませんが、[アタッチ] ウィンドウでアタッチすることはできません (おそらく、割り込みの発生が早すぎてキャッチされないため)。デバッガでプログラムを最初から開始します。 _degbugbreak() を内部的に呼び出すことで、プログラム内にブレークを生成し、デバッガにアタッチの機会を与えることができます。
void break_for_debugging() { __debugbreak(); }
実際には、割り込み 3 をトリガーするなど、他の方法もありますが、これは x86 プラットフォームでのみ機能します (ASM は C++ 64 ビットではサポートされなくなりました)。 DebugBreak() 関数もありますが、使い方があまり簡単ではないので、ここでは内部メソッドを使用することをお勧めします。
__asm int 3;
プログラムは内部メソッドを実行すると実行を停止し、プロセスにデバッガーを接続することができます。
ヒント 7: 出力ウィンドウに印刷する
DebugOutputString を呼び出すことで、デバッガーの出力ウィンドウに特定のテキストを表示できます。デバッガが接続されていない場合、この関数は何も行いません。
技巧8:隔离内存泄漏
内存泄漏是在原生开发中的一个很重要的问题,要检测内存泄漏是一个很严峻的挑战,尤其是在大型项目中。Vistual Studio可以提供检测内存泄漏的报告,还有其他的一些应用程序(免费的或商业的)也可以帮助你检测内存泄漏.有些情况下,在一些内存分配最终会导致泄漏时,可以使用调试器去中断。但是你必须找到可再现的分配编号(尽管没那么容易)。如果能做到这一点,执行程序时调试器才会中断。
我们来看下面的代码,分配了8个字节,却一直没释放分配的内存。Visual Studio提供了造成内存泄漏的对象的报告,多运行几次,会发现一直是同一个分配编号(341)。
void leak_some_memory() { char* buffer = new char[8]; } Dumping objects -> d:\marius\vc++\debuggingdemos\debuggingdemos.cpp(103) : {341} normal block at 0x00F71F38, 8 bytes long. Data: < > CD CD CD CD CD CD CD CD
在一个特定的(可复现的)位置中断的步骤如下:
确定你有足够的关于内存泄漏的报告模式(参考 使用CRT库检测内存泄漏)
多次运行程序直到你能在程序运行结束后的内存泄漏报告里找到一个可复现的分配编号,例如上个例子中的(341)
在程序一开始的地方设置一个断点以便你能够尽早地进行中断。
当最初的中断发生时,watch窗口的Name栏里会显示:{,,msvcr90d.dll}_crtBreakAlloc,在Value栏里写入你想要查找的位置编号
继续调试(F5)
程序执行到指定位置会停止,你可以使用调用栈被指引找到被该位置触发的那段代码。
遵循这些步骤, 在上个例子中,使用分配的编号(341)就可以识别内存泄漏的起因。
技巧9:调试发行版
调试和发布是两个不同的目的。调试配置是用于开发的,而发布配置,顾名思义,是用来作为程序的最终版本,因为它必须严格遵循发布的质量要求,该配置包含优化部分和调试版本的中断调试的设置。而且,有时候,要像调试调试版本一样去调试发行版。要做到这一点,你需要在配置里做一些改变。但是这种情况下,你就不再是在调试发行版,而是调试和发行的混合版
你还应该做一些事儿,以下是必须要做的:
配置C/C++ >General>Debug Information Format 应该为 “Program Database(/Zi)”
配置C/C++ >Optimization>Optimization 应该为”Disabld(/Od)”
配置Linker>Debugging>Generate Debug Info 应该为”Yes/(DEBUG)”
如图所示:
技巧10:远程调试
另一个重要的调试就是远程调试,这是一个更大的话题,多次被提到,这里我只做一下简单的概括:
你需要在远程机器上安装远程调试监控
远程调试监控必须以管理员身份运行,并且用户必须属于管理员组
在你运行监控时,会开启一个新的服务,该服务的名字必须用Visual Studio的Attach to Progress窗口的Qualifier组合框的值。
远程和本地机器上的防火墙必须允许Visual Studio和远程调试监控之间能够通信
想要调试,PDB文件是关键;为了能够让VisualStudio自动加载它们,必须满足以下条件:
1)本地的PDB文件必须可用(在远程机器的相同路径下放置一个对应的模块)。
2) 远程机器上的托管PDB文化必须可用。
结束语
Ivan Shcherbakov那篇文章和我这篇文章提到的调试技巧,在大多数的调试问题中都是必不可少的。
更多分享Visual Studio原生开发的10个调试技巧相关文章请关注PHP中文网!