ネイティブ コードのデバッグに関する FAQ

自分のプログラムを Visual Studio のデバッガーの外部で実行している場合に、アクセス違反はどのようにデバッグできますか?

[Just-In-Time デバッグ] オプションを設定し、アクセス違反が発生するまでプログラムをスタンドアロンで実行します。 その後、 [アクセス違反です] ダイアログ ボックスが表示されたら、 [キャンセル] をクリックしてデバッガーを起動します。

C++ のアクセス違反はどのようにデバッグできますか?

複数のポインターを逆参照するコード行でアクセス違反が発生する場合、どのポインターがアクセス違反を引き起こしたかを見つけるのが困難な場合があります。 Visual Studio では、例外ダイアログ ボックスにアクセス違反の原因となったポインターの名前が明示的に表示されます。

たとえば、次のコードではアクセス違反が発生します。

#include <iostream>
using namespace std;

class ClassC {
public:
  void printHello() {
    cout << "hello world";
  }
};

class ClassB {
public:
  ClassC* C;
  ClassB() {
    C = new ClassC();
  }
};

class ClassA {
public:
  ClassB* B;
  ClassA() {
    // Uncomment to fix
    // B = new ClassB();
  }
};

int main() {
  ClassA* A = new ClassA();
  A->B->C->printHello();

}

このコードを Visual Studio で実行した場合、次の例外ダイアログ ボックスが表示されます。

Screenshot of a Microsoft Visual Studio exception dialog, showing a read access violation for 'A->B was nullptr'. The Break button is selected.

ポインターがアクセス違反を引き起こした理由を特定できない場合、コードをトレースして、問題の原因となったポインターが正しく割り当てられているかどうかを確認します。 パラメーターとして渡される場合は、正常に渡され、誤って簡易コピーを作成していないことを確認します。 次に、問題のポインターに対してデータ ブレークポイントを作成し、プログラム内の別の場所で変更されていないことを確認することにより、値がプログラム内のどこかで意図せずに変更されていないことを検証します。 データ ブレークポイントの詳細については、 Using Breakpointsのデータ ブレークポイントのセクションを参照してください。

ポインターがメモリ アドレスを破壊しているかどうか見つけるには

ヒープの破損を確認してください。 メモリの破損の多くは、ヒープの破損に起因しています。 グローバル フラグ ユーティリティ (gflags.exe) または pageheap.exe を使用してください。 /windows-hardware/drivers/debugger/gflags-and-pageheap を参照してください。

メモリ アドレスの変更箇所を見つけるには:

  1. 0x00408000 にデータ ブレークポイントを設定します。 「データ変更ブレークポイントを設定する (ネイティブ C++ のみ)」を参照してください。

  2. ブレークポイントにヒットしたら、 [メモリ] ウィンドウを使用して、0x00408000 から始まるメモリの内容を表示します。 詳細については、メモリ ウィンドウに関する記事をご覧ください。

不正なパラメーター値が渡された原因はどのように見つけることができますか?

これを解決するには、次の手順に従います。

  1. 関数の先頭に位置ブレークポイントを設定します。

  2. ブレークポイントを右クリックし、 [条件] をクリックします。

  3. [ブレークポイントの条件] ダイアログ ボックスで、 [条件] チェック ボックスをオンにします。 高度なブレークポイントに関する記事を参照してください。

  4. テキスト ボックスに Var==3 などの式を入力します (Var は不適切な値が格納されるパラメーターの名前、3 はこのパラメーターに渡される不適切な値)。

  5. [true の場合] オプション ボタンをクリックし、 [OK] をクリックします。

  6. そして、再びプログラムを実行します。 Var パラメーターの値が 3 になると、ブレークポイントによって、その関数の先頭でプログラムの実行が停止します。

  7. 次に、[呼び出し履歴] ウィンドウを使用して呼び出し元の関数を見つけ、その関数のソース コードに移動します。 詳細については、[呼び出し履歴] ウィンドウを使用する」を参照してください。

ある関数が何回も呼び出される場合、どの呼び出しでエラーが発生するのかを調べるには

例: CnvtV という関数を呼び出すとプログラムでエラーが発生します。 プログラムでエラーが発生するまでに、その関数は 200 回から 300 回は呼び出されているようです。 CnvtV に位置ブレークポイントを設定すると、この関数を呼び出すたびにプログラムが停止してしまうため、このブレークポイントは使用したくありません。 どのような条件で呼び出しが失敗するのかが不明なため、条件付きブレークポイントは設定できません。 どうしたらいいのでしょうか。

[ヒット カウント] フィールドを使って、関数のブレークポイントに、絶対に到達不可能な大きい値を設定できます。 この場合、CnvtV 関数が 200 回から 300 回は呼び出されているようなので、 [ヒット カウント] に 1000 以上の値を設定します。 その後、プログラムを実行し、エラーが発生するのを待ちます。 エラーが発生したら、[ブレークポイント] ウィンドウを開き、ブレークポイントの一覧を確認します。 CnvtV に設定されたブレークポイントは、次のように、後ろにヒット カウントと残りの繰り返し回数が付いた状態で表示されます。

CnvtV(int) (no condition) when hit count is equal to 1000 (currently 101)

この関数は、101 回目の呼び出しで失敗したことがわかります。 ヒット カウントを 101 にしてブレークポイントを設定し直し、プログラムを再び実行します。すると、エラーの原因となった CnvtV 呼び出しのところでプログラムが停止します。

Win32 のエラー コードを調べるには

既定のシステム インストールの INCLUDE ディレクトリの WINERROR.H に、Win32 API 関数のエラー コード定義が含まれています。

エラー コードを検索するには、 [ウォッチ] ウィンドウまたは [クイック ウォッチ] ダイアログ ボックスに、検索対象のコードを入力します。 次に例を示します。

0x80000004,hr

自分のアプリをステップ実行しているときにフォーカスを保持するにはどうすればよいですか?

例: プログラムで、ウィンドウのアクティブ化が正しく動作しません。 デバッガーでプログラムをステップ実行すると、プログラムがフォーカスを保持できないため、問題を再現できなくなります。 フォーカスが失われないようにする方法はありますか?

コンピューターがもう 1 台ある場合は、リモート デバッグを行います。 リモート コンピューター上でプログラムを操作し、ホスト上でデバッガーを実行します。 詳細については、リモート コンピューターを選択する」を参照してください。

Windows API 関数をデバッグするには

NT シンボルを読み込んだ状態で Windows API 関数にブレークポイントを設定するには:

  • 関数のブレークポイントに、関数が存在する DLL の名前と共に関数名を入力します (コンテキスト演算子に関するページを参照してください)。 32 ビット コードでは、関数名の装飾形式を使用します。 たとえば、MessageBeep にブレークポイントを設定するには、次のように入力します。

    {,,USER32.DLL}_MessageBeep@4
    

    装飾名を取得するには、「装飾名の表示」を参照してください 。

    装飾名をテストし、逆アセンブリ コードで表示できます。 Visual Studio デバッガーの関数で一時停止しているときに、コード エディターまたは呼び出し履歴ウィンドウで関数を右クリックし、 [逆アセンブリへ移動] を選択します。

  • 64 ビット コードでは、非装飾名を使用できます。

    {,,USER32.DLL}MessageBeep
    

次の手順

Visual Studio でのネイティブ コード デバッグの詳細については、次のリンクを参照してください。