次の方法で共有


初心者向けのデバッグ

ソフトウェア開発者として記述するコードは、必ずしも期待どおりに動作するとは限りません。 時には、それは全く異なる何かを行います! 予期しない状況が発生した場合、次のタスクは理由を見つけ出す作業です。また、コードを何時間も見つめ続けたくなるかもしれませんが、デバッグ ツールまたはデバッガーを使用する方が簡単で効率的です。

残念ながら、デバッガーは、コード内のすべての問題や "バグ" を魔法のように明らかにできるものではありません。 デバッグ は、Visual Studio などのデバッグ ツールでコードを段階的に実行し、プログラミングミスを犯した正確なポイントを見つけることを意味します。 その後、コードおよびデバッグ ツールで行う必要がある修正内容を理解すると、多くの場合、プログラムの実行を続行できるように一時的な変更を行うことができます。

デバッガーを効果的に使用することは、学習に時間と練習を要するスキルでもありますが、最終的にはすべてのソフトウェア開発者にとって基本的なタスクです。 この記事では、デバッグの基本原則を紹介し、開始するためのヒントを提供します。

自分に正しい質問をして問題を明確にする

修正を試みる前に発生した問題を明確にするのに役立ちます。 コードで既に問題が発生していることを想定しています。そうしないと、デバッグ方法を理解しようとはならないでしょう。 そのため、デバッグを開始する前に、解決しようとしている問題が特定されていることを確認してください。

  • コードで何を行うと予想されましたか?

  • 代わりに何が起こりましたか?

    アプリの実行中にエラー(例外)が発生した場合、それは良いことかもしれません! 例外は、コードの実行時に予期しないイベントが発生し、通常は何らかのエラーが発生します。 デバッグ ツールを使用すると、例外が発生したコード内の正確な場所に行き、考えられる修正プログラムを調査するのに役立ちます。

    何か他の問題が発生した場合、問題の症状は何ですか? コードでこの問題が発生した場所を既に疑っていますか? たとえば、コードにテキストが表示されていても、テキストが正しくない場合は、データが正しくないか、表示テキストを設定するコードに何らかのバグがあることがわかります。 デバッガーでコードをステップ実行することで、変数に対する各変更を調べて、正しくない値が割り当てられているタイミングと方法を正確に検出できます。

前提条件を調べる

バグやエラーを調査する前に、特定の結果が予想される前提条件を考えてください。 デバッガーで問題の原因を見つめていても、隠れているまたは不明な仮定が問題の特定を妨げることがあります。 考えられる前提条件の長いリストがあるかもしれません。 前提条件に挑戦するために自分自身に質問する必要がある質問をいくつか次に示します。

  • 適切な API (つまり、適切なオブジェクト、関数、メソッド、またはプロパティ) を使用していますか? 使用している API は、思った動作を行わない可能性があります。 (デバッガーで API 呼び出しを調べた後、修正するには、正しい API を識別するためにドキュメントへの旅行が必要な場合があります)。

  • API を正しく使用していますか? おそらく、適切な API を使用しましたが、正しい方法で使用しませんでした。

  • コードに入力ミスが含まれていますか? 変数名の単純なスペルミスなど、一部の入力ミスは、特に変数を使用する前に宣言する必要のない言語を使用する場合に、見にくい場合があります。

  • コードに変更を加え、それが表示されている問題とは無関係であると想定しましたか?

  • 実際に発生した内容とは異なる特定の値 (または特定の型の値) がオブジェクトまたは変数に含まれていることが予想されましたか?

  • コードの意図を知っていますか? 多くの場合、他のユーザーのコードをデバッグすることはより困難です。 コードでない場合は、コードを効果的にデバッグする前に、コードの動作を正確に学習するために時間を費やす必要がある可能性があります。

    アドバイス

    コードを記述するときは、小さく始めて、動作するコードから始めてください。 (ここでは、適切なサンプル コードが役立ちます)。場合によっては、達成しようとしているコア タスクを示す小さなコードから始めることで、大規模または複雑なコード セットを修正する方が簡単な場合があります。 その後、コードを段階的に変更または追加し、各時点でエラーをテストできます。

想定に疑問を投げかけることで、コードで問題を見つけるのにかかる時間を短縮できます。 また、問題の解決にかかる時間を短縮することもできます。

デバッグ モードでコードをステップ実行して、問題が発生した場所を見つけます

通常、アプリを実行すると、コードの実行後にのみエラーと正しくない結果が表示されます。 また、理由を伝えずに、プログラムが予期せず終了する場合もあります。

デバッガー内でアプリを実行すると(デバッグ モードとも呼ばれます)、デバッガーはプログラムの実行中に発生するすべてのことをアクティブに監視します。 また、アプリを任意の時点で一時停止して状態を確認し、コードを 1 行ずつステップ実行して、すべての詳細を確認することもできます。

Visual Studio では、F5 使用してデバッグ モードに切り替えます (または、[デバッグデバッグの開始] メニュー コマンドまたは [デバッグの 開始] ボタンを示す [デバッグ の開始] ボタン アイコンを使用します。デバッグ ツール バーの)。 例外が発生した場合、Visual Studio の例外ヘルパーは、例外が発生した正確なポイントに移動し、他の役に立つ情報を提供します。 コード内の例外を処理する方法の詳細については、「デバッグ手法とツールの」を参照してください。

例外が発生しなかった場合は、コード内の問題を探す場所を適切に把握している可能性があります。 この手順では、デバッガーで ブレークポイント を使用して、コードをより慎重に調べる機会を得ることができます。 ブレークポイントは、信頼性の高いデバッグの最も基本的で不可欠な機能です。 ブレークポイントは、Visual Studio で実行中のコードを一時停止する場所を示します。そのため、コードが実行されるシーケンスの変数の値またはメモリの動作を確認できます。

Visual Studio では、コード行の横にある左余白をクリックすると、ブレークポイントをすばやく設定できます。 または、行にカーソルを置き、F9押します。

これらの概念を説明するために、既にいくつかのバグがあるコード例を説明します。 C# を使用していますが、デバッグ機能は Visual Basic、C++、JavaScript、Python、およびその他のサポートされている言語に適用されます。 Visual Basic のサンプル コードも提供されていますが、スクリーンショットは C# にあります。

サンプル アプリを作成する (いくつかのバグあり)

次に、いくつかのバグがあるアプリケーションを作成します。

  1. Visual Studio がインストールされていて、.NET デスクトップ開発 ワークロードがインストールされている必要があります。

    Visual Studio をまだインストールしていない場合は、Visual Studio のダウンロード ページに移動して無料でインストールします。

    ワークロードをインストールする必要があるが、既に Visual Studio がある場合は、[ツール][ツールと機能の取得]選択します。 Visual Studio インストーラーが起動します。 [.NET デスクトップ開発] ワークロードを選んでから、[変更] を選びます。

  2. Visual Studio を開きます。

    スタート ウィンドウで、[新しいプロジェクト作成] を選択します。 検索ボックス コンソール を入力し、C# 選択するか、Visual Basic を言語として してから、.NET 用コンソール アプリ 選択します。 次にを選択し、次にを選びます。 プロジェクト名として ConsoleApp_FirstApp を入力し、[次へ]選択します。

    別のプロジェクト名を使用する場合は、サンプル コードをコピーするときに、プロジェクト名と一致するように名前空間の値を変更する必要があります。

    推奨されるターゲット フレームワークまたは .NET 8 を選択し、次に 作成を選択します。

    .NET 用の コンソール アプリ プロジェクト テンプレートが表示されない場合は、[ツール]>[ツールと機能の取得]に移動すると、Visual Studio インストーラーが開きます。 [.NET デスクトップ開発] ワークロードを選んでから、[変更] を選びます。

    Visual Studio によってコンソール プロジェクトが作成され、右側のウィンドウ ソリューション エクスプローラー に表示されます。

  3. Program.cs (または Program.vb) で、すべての既定のコードを次のコードに置き換えます。 (最初に、適切な言語タブ (C# または Visual Basic) を選択します)。

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp_FirstApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Welcome to Galaxy News!");
                IterateThroughList();
                Console.ReadKey();
            }
    
            private static void IterateThroughList()
            {
                var theGalaxies = new List<Galaxy>
            {
                new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')},
                new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')},
                new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')},
                new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')},
                new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')},
                new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')}
            };
    
                foreach (Galaxy theGalaxy in theGalaxies)
                {
                    Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
                }
    
                // Expected Output:
                //  Tadpole  400,  Spiral
                //  Pinwheel  25,  Spiral
                //  Cartwheel, 500,  Lenticular
                //  Small Magellanic Cloud .2,  Irregular
                //  Andromeda  3,  Spiral
                //  Maffei 1,  11,  Elliptical
            }
        }
    
        public class Galaxy
        {
            public string Name { get; set; }
    
            public double MegaLightYears { get; set; }
            public object GalaxyType { get; set; }
    
        }
    
        public class GType
        {
            public GType(char type)
            {
                switch(type)
                {
                    case 'S':
                        MyGType = Type.Spiral;
                        break;
                    case 'E':
                        MyGType = Type.Elliptical;
                        break;
                    case 'l':
                        MyGType = Type.Irregular;
                        break;
                    case 'L':
                        MyGType = Type.Lenticular;
                        break;
                    default:
                        break;
                }
            }
            public object MyGType { get; set; }
            private enum Type { Spiral, Elliptical, Irregular, Lenticular}
        }
    }
    

    このコードの目的は、銀河名、銀河までの距離、および銀河の種類をすべて一覧に表示することです。 デバッグするには、コードの意図を理解することが重要です。 出力に表示するリストの 1 行の形式を次に示します。

    銀河の名前距離銀河型

アプリを実行する

F5 キーを押すか、コード エディターの上にあるデバッグ ツール バーの [デバッグの開始] ボタン [デバッグの開始] ボタンを示すアイコン。 を選びます。

デバッグツールに例外が表示されることなく、アプリが起動します。 ただし、コンソール ウィンドウに表示される出力は期待した内容ではありません。 予想される出力を次に示します。

Tadpole  400,  Spiral
Pinwheel  25,  Spiral
Cartwheel, 500,  Lenticular
Small Magellanic Cloud .2,  Irregular
Andromeda  3,  Spiral
Maffei 1,  Elliptical

ただし、代わりに次の出力が表示されます。

Tadpole  400,  ConsoleApp_FirstApp.GType
Pinwheel  25,  ConsoleApp_FirstApp.GType
Cartwheel, 500,  ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2,  ConsoleApp_FirstApp.GType
Andromeda  3,  ConsoleApp_FirstApp.GType
Maffei 1, 11,  ConsoleApp_FirstApp.GType

出力とコードを見ると、GType は銀河型を格納するクラスの名前であることがわかります。 クラス名ではなく、実際の銀河の種類 ("スパイラル" など) を表示しようとしています。

アプリをデバッグする

  1. アプリがまだ実行されている状態で、ブレークポイントを挿入します。

    ループで、 メソッドの横を右クリックしてコンテキスト メニューを取得し、ポップアップ メニューから [ブレークポイント][ブレークポイントの挿入] 選択します。

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
    }
    

    ブレークポイントを設定すると、左側の余白に赤い点が表示されます。

    出力に問題がある場合は、デバッガーで出力を設定する上記のコードを参照してデバッグを開始します。

  2. [デバッグ] ツールバーの [RestartApp]\(再起動\) ボタンを示す Restartアイコンを選択します。[デバッグ] ツール バーの [] ボタン (Ctrl + Shift + F5)。

    設定したブレークポイントでアプリが一時停止します。 黄色の強調表示は、デバッガーが一時停止されている場所を示します (黄色のコード行はまだ実行されていません)。

  3. 右側の GalaxyType 変数にカーソルを合わせ、次に、レンチアイコンの左側にある theGalaxy.GalaxyTypeを展開してください。 GalaxyType にプロパティ MyGTypeが含まれており、プロパティ値が Spiralに設定されていることがわかります。

    Visual Studio デバッガーのスクリーンショット。コード行が黄色で、Galaxy GalaxyType プロパティの下にメニューが開いています。

    "スパイラル" は、実際にはコンソールに印刷する予定だった正しい値です。 そのため、アプリの実行中にこのコードの値にアクセスできることは良いスタートです。 このシナリオでは、正しくない API を使用しています。 デバッガーでコードを実行しているときにこれを修正できるかどうかを見てみましょう。

  4. 同じコードで、デバッグ中にカーソルを theGalaxy.GalaxyType の最後に置き、theGalaxy.GalaxyType.MyGTypeに変更します。 編集はできますが、コード エディターにエラー (赤い波線) が表示されます。 (Visual Basic では、エラーは表示されず、コードのこのセクションは機能します)。

  5. F11 (デバッグ>ステップ イン またはデバッグ ツール バーの [ステップ イン] ボタン) を押して、現在のコード行を実行します。

    F11 は、デバッガーを一度に 1 つのステートメントに進めてコードを実行します。 F10 (ステップ オーバー) も同様のコマンドであり、どちらもデバッガーの使用方法を学習するときに役立ちます。

    デバッガーを進めようとすると、[ホット リロード] ダイアログ ボックスが表示され、編集をコンパイルできないことが示されます。

    コード行が赤で強調表示され、[編集] オプションが選択されたメッセージ ボックスが表示された Visual Studio デバッガーのスクリーンショット。

    [エディット コンティニュ] ダイアログ ボックスが表示され、編集をコンパイルできないことが示されます。

    コード行が赤で強調表示され、[編集] オプションが選択されたメッセージ ボックスが表示された Visual Studio デバッガーのスクリーンショット。

    手記

    Visual Basic サンプル コードをデバッグする場合は、デバッグ ツール バーの [アプリの再起動] ボタンを示す [再起動]アイコンをクリックするように指示されるまで、次のいくつかの手順をスキップします。 ボタン。

  6. [ホット リロード] または [エディット コンティニュ] メッセージ ボックスで、[編集] を選びます。 エラー一覧の ウィンドウにエラー メッセージが表示されます。 このエラーは、'object'MyGTypeの定義が含まれていないことを示します。

    コード行が赤で強調表示され、エラー一覧ウィンドウに 2 つのエラーが表示されている Visual Studio デバッガーのスクリーンショット。

    MyGType プロパティを持つ GType 型のオブジェクトを持つ各銀河を設定しても、デバッガーは theGalaxy オブジェクトを GType型のオブジェクトとして認識しません。 どうなっているのですか。 あなたは銀河の種類を設定するコードを見直したいと思っています。 これを行うと、GType クラスに MyGTypeのプロパティがあることがわかりますが、何かが正しくありません。 object に関するエラーメッセージが手掛かりであることが判明しました。言語インタープリターに対して、型は GType型のオブジェクトではなく、object 型のオブジェクトのように見えます。

  7. 銀河型の設定に関連するコードを見ると、GTypeの代わりに Galaxy クラスの GalaxyType プロパティが object として指定されていることがわかります。

    public object GalaxyType { get; set; }
    
  8. 上記のコードを次のように変更します。

    public GType GalaxyType { get; set; }
    
  9. [デバッグ] ツール バーの [アプリの再起動] ボタンを示す再起動アイコン 選択します。デバッグ ツール バーの [] ボタン (CtrlShiftF5) をクリックして、コードを再コンパイルして再起動します。

    これで、デバッガーが Console.WriteLineで一時停止すると、theGalaxy.GalaxyType.MyGType上にマウス ポインターを合わせ、値が正しく設定されていることを確認できます。

  10. ブレークポイントを削除するには、左側の余白にあるブレークポイントの円をクリックして (または右クリックして [ブレークポイント削除]を選択 )、F 5 キー 押して続行します。

    アプリが実行され、出力が表示されます。 見栄えは良いですが、1 つのことに気付きます。 あなたは、小さなマゼラン雲の銀河がコンソール出力に不規則な銀河として現れるのを期待しましたが、それは全く銀河の種類を示していません。

    Tadpole  400,  Spiral
    Pinwheel  25,  Spiral
    Cartwheel, 500,  Lenticular
    Small Magellanic Cloud .2,
    Andromeda  3,  Spiral
    Maffei 1,  Elliptical
    
  11. switch ステートメントの前 (Visual Basic の Select ステートメントの前) に、このコード行にブレークポイントを設定します。

    public GType(char type)
    

    このコードは銀河の種類が設定されている場所であるため、詳しく見てみたいと思います。

  12. 再起動するには、デバッグ ツール バーの [再起動][デバッグ] ツール バーの [アプリの再起動] ボタンを示すアイコン。 ボタン (Ctrl + Shift + F5 キー) を選びます。

    デバッガーは、ブレークポイントを設定したコード行で一時停止します。

  13. type 変数にカーソルを合わせます。 S の値が表示されます (文字コードの後)。 Iの値に興味があるのは、それが不規則銀河型であることを知っているからです。

  14. F5 押し、もう一度 変数にカーソルを合わせます。 type 変数に I の値が表示されるまで、この手順を繰り返します。

    黄色のコード行と、型変数の値が 73 I のウィンドウを含む Visual Studio デバッガーのスクリーンショット。

  15. 次に、F11 押します (デバッグステップ イン)。

  16. F11 キーを押し、'I' の値に対する switch ステートメントのコード行で停止するまで続けます (Visual Basic の場合はSelect ステートメント)。 ここでは、入力ミスの結果として生じる明確な問題が表示されます。 コードは、MyGType を不規則な銀河型として設定する場所に進む必要がありますが、代わりにデバッガーはこのコードを完全にスキップし、switch ステートメント (Visual Basic のElse ステートメント) の default セクションで一時停止します。

    入力ミスのエラーを示すスクリーンショット。

    コードを見ると、case 'l' ステートメントに入力ミスが表示されます。 それは case 'I'であるべきです。

  17. case 'l' のコードを選択し、case 'I'に置き換えます。

  18. ブレークポイントを削除し、[再起動] ボタンを選択してアプリを再起動します。

    バグが修正され、期待される出力が表示されます。

    任意のキーを押してアプリを終了します。

概要

問題が発生した場合は、デバッガーと ステップ コマンド (F10F11 など) を使用して、問題のあるコード領域を見つけます。

手記

問題が発生したコードの領域を特定することが困難な場合は、問題が発生する前に実行されるコードにブレークポイントを設定し、問題のマニフェストが表示されるまでステップ コマンドを使用します。 tracepoints を使用して、出力 ウィンドウにメッセージを記録することもできます。 ログに記録されたメッセージを調べて (まだログに記録されていないメッセージを確認します)、多くの場合、問題のあるコードの領域を特定できます。 このプロセスを何度か繰り返して絞り込む必要がある場合があります。

問題のあるコードの領域が見つかると、デバッガーを使用して調査します。 問題の原因を見つけるには、デバッガーでアプリを実行しているときに問題のコードを調べます。

  • 変数 を検査し、変数に含める必要がある値の型が含まれているかどうかを確認します。 正しくない値が見つかると、正しくない値が設定された場所を確認します (値が設定された場所を見つけるには、デバッガーを再起動するか、呼び出し履歴を確認するか、またはその両方を確認する必要があります)。

  • アプリケーションが想定したコードを実行しているかどうかを確認します。 (たとえば、サンプル アプリケーションでは、switch ステートメントのコードで銀河の種類を [不規則] に設定することが想定されていましたが、入力ミスが原因でアプリによってコードがスキップされました)。

ヒント

バグを見つけるのに役立つデバッガーを使用します。 デバッグ ツールは、コードの意図がわかっている場合にのみ、"自動的に" バグを発見できます。 ツールは、開発者がその意図を表現している場合にのみ、コードの意図を知ることができます。 それを行う方法は、単体テストを書くことです。

次の手順

この記事では、いくつかの一般的なデバッグの概念について学習しました。 次に、デバッガーの詳細について学習を開始できます。