教程:了解如何使用 Visual Studio 调试 C++ 代码Tutorial: Learn to debug C++ code using Visual Studio

本文通过分步演练介绍了 Visual Studio 调试器的功能。This article introduces the features of the Visual Studio debugger in a step-by-step walkthrough. 如果需要更加深入地了解调试器功能,请参阅初探调试器If you want a higher-level view of the debugger features, see First look at the debugger. 当你调试应用时,通常意味着运行附带有调试器的应用程序 。When you debug your app, it usually means that you are running your application with the debugger attached. 执行此操作时,调试器在运行过程中可提供许多方法让你查看代码的情况。When you do this, the debugger provides many ways to see what your code is doing while it runs. 你可以逐步浏览代码、查看变量中存储的值、设置对变量的监视以查看值何时改变、检查代码的执行路径、查看代码分支是否正在运行等等。You can step through your code and look at the values stored in variables, you can set watches on variables to see when values change, you can examine the execution path of your code, see whether a branch of code is running, and so on. 如果这是你第一次尝试调试代码,可能需要在浏览本文之前阅读零基础调试If this is the first time that you've tried to debug code, you may want to read Debugging for absolute beginners before going through this article.

虽然演示应用为 C++,但大多数功能都适用于 C#、Visual Basic、F#、Python、JavaScript 和 Visual Studio 支持的其他语言(F# 不支持“编辑并继续”。Although the demo app is C++, most of the features are applicable to C#, Visual Basic, F#, Python, JavaScript, and other languages supported by Visual Studio (F# does not support Edit-and-continue. F# 和 JavaScript 不支持“自动”窗口 )。F# and JavaScript do not support the Autos window). 屏幕截图为 C++。The screenshots are in C++.

在本教程中,你将:In this tutorial, you will:

  • 启动调试器并命中断点。Start the debugger and hit breakpoints.
  • 了解在调试器中逐步执行代码的命令Learn commands to step through code in the debugger
  • 检查数据提示和调试器窗口中的变量Inspect variables in data tips and debugger windows
  • 检查调用堆栈Examine the call stack

先决条件Prerequisites

须安装 Visual Studio 2019 且具有“使用 C++ 的桌面开发”工作负载 。You must have Visual Studio 2019 installed and the Desktop development with C++ workload.

须安装 Visual Studio 2017 且具有“C++ 桌面开发”工作负载 。You must have Visual Studio 2017 installed and the Desktop development with C++ workload.

如果尚未安装 Visual Studio,请转到 Visual Studio 下载页免费安装。If you haven't already installed Visual Studio, go to the Visual Studio downloads page to install it for free.

如果尚未安装 Visual Studio,请转到 Visual Studio 下载页免费安装。If you haven't already installed Visual Studio, go to the Visual Studio downloads page to install it for free.

如果需要安装工作负载但已有 Visual Studio,请转到“工具” > “获取工具和功能...” ,这会打开 Visual Studio 安装程序。If you need to install the workload but already have Visual Studio, go to Tools > Get Tools and Features..., which opens the Visual Studio Installer. Visual Studio 安装程序启动。The Visual Studio Installer launches. 选择“使用 C++ 的桌面开发”工作负载,然后选择“修改”按钮 。Choose the Desktop development with C++ workload, then choose Modify.

创建项目Create a project

首先,创建 C++ 控制台应用程序项目。First, you'll create a C++ console application project. 项目类型随附了所需的全部模板文件,无需添加任何内容!The project type comes with all the template files you'll need, before you've even added anything!

  1. 打开 Visual Studio 2017。Open Visual Studio 2017.

  2. 从顶部菜单栏中选择“文件”>“新建”>“项目” 。From the top menu bar, choose File > New > Project.

  3. 在“新建项目”对话框左侧的窗格中,展开“Visual C++”,然后选择“Windows 桌面” 。In the New Project dialog box in the left pane, expand Visual C++ and then choose Windows Desktop. 在中间窗格中,选择“Windows 控制台应用程序” 。In the middle pane, choose Windows Console Application. 然后将项目命名为 get-started-debugging 。Then name the project get-started-debugging.

    如果没有看到“控制台应用”项目模板,请选择“新建项目”对话框左侧窗格中的“打开 Visual Studio 安装程序”链接 。If you don't see the Console App project template, choose the Open Visual Studio Installer link in the left pane of the New Project dialog box. Visual Studio 安装程序启动。The Visual Studio Installer launches. 选择“.NET Core 跨平台开发”工作负载,然后选择“修改” 。Choose the .NET Core cross-platform development workload, and then choose Modify.

  4. 单击 “确定”Click OK.

    此时,Visual Studio 将打开新项目。Visual Studio opens your new project.

  1. 打开 Visual Studio 2019。Open Visual Studio 2019.

    如果开始窗口未打开,请选择“文件”>“开始窗口” 。If the start window is not open, choose File > Start Window.

  2. 在“开始”窗口上,选择“创建新项目” 。On the start window, choose Create a new project.

  3. 在“创建新项目”窗口的搜索框中输入或键入“控制台” 。On the Create a new project window, enter or type console in the search box. 接下来,从“语言”列表中选择“C++”,然后从“平台”列表中选择“Windows” 。Next, choose C++ from the Language list, and then choose Windows from the Platform list.

    应用语言和平台筛选器之后,选择“控制台应用”模板,然后选择“下一步” 。After you apply the language and platform filters, choose the Console App template, and then choose Next.

    为“控制台应用”选择 C++ 模板

    备注

    如果未看到“控制台应用”模板,则可以通过“创建新项目”窗口安装该模板 。If you do not see the Console App template, you can install it from the Create a new project window. 在“找不到所需内容?”消息中,选择“安装更多工具和功能”链接 。In the Not finding what you're looking for? message, choose the Install more tools and features link. 然后,在 Visual Studio 安装程序中,选择“使用 C++ 的桌面开发”工作负载 。Then, in the Visual Studio Installer, choose the Desktop development with C++ workload.

  4. 在“配置新项目”窗口中,在“项目名称”框中键入或输入“get-started-debugging” 。In the Configure your new project window, type or enter get-started-debugging in the Project name box. 然后,选择“创建” 。Then, choose Create.

    此时,Visual Studio 将打开新项目。Visual Studio opens your new project.

创建应用程序Create the application

  1. 在 get-started-debugging.cpp 中,使用以下代码替换所有默认代码 :In get-started-debugging.cpp, replace all of the default code with the following code instead:

    #include <string>
    #include <vector>
    #include <iostream>
    
    void SendMessage(const std::wstring& name, int msg)
    {
        std::wcout << L"Hello, " << name << L"! Count to " << msg << std::endl;
    }
    
    int main()
    {
        std::vector<wchar_t> letters = { L'f', L'r', L'e', L'd', L' ', L's', L'm', L'i', L't', L'h' };
        std::wstring name = L"";
        std::vector<int> a(10);
        std::wstring key = L"";
    
        for (int i = 0; i < letters.size(); i++)
        {
            name += letters[i];
            a[i] = i + 1;
            SendMessage(name, a[i]);
        }
        std::wcin >> key;
        return 0;
    }
    

启动调试器!Start the debugger!

  1. 按 F5 (“调试”>“开始调试” )或调试工具栏中的“开始调试” 按钮开始调试Press F5 (Debug > Start Debugging) or the Start Debugging button Start Debugging in the Debug Toolbar.

    通过 F5 启动应用时,调试器会附加到应用进程,但现在我们还未执行任何特殊操作来检查代码。F5 starts the app with the debugger attached to the app process, but right now we haven't done anything special to examine the code. 因此应用只会加载,控制台输出如你所见。So the app just loads and you see the console output.

    Hello, f! Count to 1
    Hello, fr! Count to 2
    Hello, fre! Count to 3
    Hello, fred! Count to 4
    Hello, fred ! Count to 5
    Hello, fred s! Count to 6
    Hello, fred sm! Count to 7
    Hello, fred smi! Count to 8
    Hello, fred smit! Count to 9
    Hello, fred smith! Count to 10
    

    在本教程中,我们将使用调试器仔细查看此应用,并查看调试器功能。In this tutorial, we'll take a closer look at this app using the debugger and get a look at the debugger features.

  2. 按红色的停止停止调试按钮 (Shift + F5) 来停止调试器 。Stop the debugger by pressing the red stop Stop Debugging button (Shift + F5).

  3. 在控制台窗口中,按某个键和 Enter 来关闭控制台窗口 。In the console window, press a key and Enter to close the console window.

设置断点并启动调试器Set a breakpoint and start the debugger

  1. main 函数的 for 循环中,通过单击以下代码行的左边距来设置断点:In the for loop of the main function, set a breakpoint by clicking the left margin of the following line of code:

    name += letters[i];

    设置断点的位置会出现一个红色圆圈的断点A red circle Breakpoint appears where you set the breakpoint.

    断点是可靠调试的最基本和最重要的功能之一。Breakpoints are one of the most basic and essential features of reliable debugging. 断点指示 Visual Studio 应在哪个位置挂起你的运行代码,以使你可以查看变量的值或内存的行为,或确定代码的分支是否运行。A breakpoint indicates where Visual Studio should suspend your running code so you can take a look at the values of variables, or the behavior of memory, or whether or not a branch of code is getting run.

  2. 按“F5” 或“开始调试” 按钮开始调试,应用随即启动,调试器将运行到你设置断点的代码行。Press F5 or the Start Debugging button Start Debugging, the app starts, and the debugger runs to the line of code where you set the breakpoint.

    设置并命中断点

    黄色箭头表示调试器暂停处的语句,它还在同一点上暂停应用执行(此语句尚未执行)。The yellow arrow represents the statement on which the debugger paused, which also suspends app execution at the same point (this statement has not yet executed).

    如果应用尚未运行,则按 F5 会启动调试器并在第一个断点处停止 。If the app is not yet running, F5 starts the debugger and stops at the first breakpoint. 否则,按 F5 将继续运行应用至下一个断点 。Otherwise, F5 continues running the app to the next breakpoint.

    当你知道要详细检查的代码行或代码段时,断点功能非常有用。Breakpoints are a useful feature when you know the line of code or the section of code that you want to examine in detail. 有关可设置的不同类型断点(如条件断点)的信息,请参阅使用断点For information on the different types of breakpoints you can set, such as conditional breakpoints, see Using breakpoints.

大多数情况下,我们使用键盘快捷方式,因为这是在调试器中快速执行应用的好方法(括号中显示了等效的命令,如菜单命令)。Mostly, we use the keyboard shortcuts here, because it's a good way to get fast at executing your app in the debugger (equivalent commands such as menu commands are shown in parentheses).

  1. main 方法中的 for 循环中暂停时,按两次 F11(或选择“调试”>“单步执行”)前进到 SendMessage 方法调用 。While paused in the for loop in the main method, press F11 (or choose Debug > Step Into) twice to to advance to the SendMessage method call.

    按两次 F11 后,应位于以下代码行 :After pressing F11 twice, you should be at this line of code:

    SendMessage(name, a[i]);

  2. 再按一次 F11 单步执行到 SendMessage 方法 。Press F11 one more time to step into the SendMessage method.

    黄色指针会前进到 SendMessage 方法。The yellow pointer advances into the SendMessage method.

    使用 F11 单步执行代码Use F11 to Step Into code

    F11 是“单步执行”命令,每按一次,应用就执行下一个语句 。F11 is the Step Into command and advances the app execution one statement at a time. F11 是一种以最详尽方式检查执行流的好方法。F11 is a good way to examine the execution flow in the most detail. (为了更快地浏览代码,我们还向你展示一些其他选项。)默认情况下,调试器会跳过非用户代码(如果需要更多详细信息,请参阅仅我的代码)。(To move faster through code, we show you some other options also.) By default, the debugger skips over non-user code (if you want more details, see Just My Code).

    假设你已完成了对 SendMessage 方法的检查,并且希望退出该方法但保持位于调试器中。Let's say that you are done examining the SendMessage method, and you want to get out of the method but stay in the debugger. 可使用“单步跳出”命令执行此操作 。You can do this using the Step Out command.

  3. 按 Shift + F11(或“调试”>“单步跳出”) 。Press Shift + F11 (or Debug > Step Out).

    此命令将恢复应用执行(并使调试器前进),直到当前方法或函数返回。This command resumes app execution (and advances the debugger) until the current method or function returns.

    你应当回到 main 方法的 for 循环,在 SendMessage 方法调用处暂停。You should be back in the for loop in the main method, paused at the SendMessage method call.

  4. 多按几次 F11,直到再次返回到 SendMessage 方法调用 。Press F11 several times until you get back to the SendMessage method call again.

  5. 在方法调用处暂停时,按一次 F10(或选择“调试”>“单步跳过”) 。While paused at the method call, press F10 (or choose Debug > Step Over) once.

    使用 F10 单步跳过代码Use F10 to Step Over code

    请注意,这次调试器不会单步执行 SendMessage 方法。Notice this time that the debugger does not step into the SendMessage method. 按 F10 将使调试器前进,但不会单步执行应用代码中的函数或方法(代码仍将执行) 。F10 advances the debugger without stepping into functions or methods in your app code (the code still executes). 通过在进行 SendMessage 方法调用时按“F10”(而不是“F11”),我们跳过了 SendMessage 的实现代码(我们现在可能对此不感兴趣) 。By pressing F10 on the SendMessage method call (instead of F11), we skipped over the implementation code for SendMessage (which maybe we're not interested in right now). 有关在代码中进行移动的不同方法的详细信息,请参阅浏览调试器中的代码For more information on different ways to move through your code, see Navigate code in the debugger.

  1. 按 F5 前进到断点 。Press F5 to advance to the breakpoint.

  2. 在代码编辑器中,向下滚动并将鼠标悬停在 SendMessage 方法中的 std::wcout 函数上,直到左侧出现绿色的“运行时单击”按钮运行时单击In the code editor, scroll down and hover over the std::wcout function in the SendMessage method until the green Run to Click button Run to Click appears on the left. 按钮的工具提示显示“将执行运行到此处”。The tooltip for the button shows "Run execution to here".

    使用“运行时单击”功能Use the Run to Click feature

    备注

    “运行时单击”是 Visual Studio 2017Visual Studio 2017 中的新增按钮 。The Run to Click button is new in Visual Studio 2017Visual Studio 2017. (如果未看到绿色箭头按钮,请在此示例中改为使用 F11 以使调试器前进到正确的位置。 )(If you don't see the green arrow button, use F11 in this example instead to advance the debugger to the right place.)

  3. 单击“运行时单击” 按钮运行时单击Click the Run to Click button Run to Click.

    调试器会前进到 std::wcout 函数。The debugger advances to the std::wcout function.

    使用此按钮类似于设置临时断点。Using this button is similar to setting a temporary breakpoint. “运行时单击”对于快速到达应用代码的可见区域十分方便(你可在任何打开的文件中单击) 。Run to Click is handy for getting around quickly within a visible region of app code (you can click in any open file).

快速重启应用Restart your app quickly

单击调试工具栏中的“重启”重启应用按钮 (Ctrl + Shift + F5) 。Click the Restart Restart App button in the Debug Toolbar (Ctrl + Shift + F5).

当你按下“重启”时,与停止应用并重启调试器相比,它节省了时间 。When you press Restart, it saves time versus stopping the app and restarting the debugger. 调试器在执行代码命中的第一个断点处暂停。The debugger pauses at the first breakpoint that is hit by executing code.

调试器再次在你之前在 for 循环上设置的断点处停止。The debugger stops again at the breakpoint you previously set inside the for loop.

使用数据提示检查变量Inspect variables with data tips

允许你检查变量的功能是调试器最有用的功能之一,并且有不同的方法来执行此操作。Features that allow you to inspect variables are one of the most useful features of the debugger, and there are different ways to do it. 通常,当尝试调试问题时,你试图找出变量是否存储了你期望它们在特定时间具有的值。Often, when you try to debug an issue, you are attempting to find out whether variables are storing the values that you expect them to have at a particular time.

  1. name += letters[i] 语句上暂停时,将鼠标悬停在 letters 变量上,会看到其默认值 size={10}While paused on the name += letters[i] statement, hover over the letters variable and you see it's default value, size={10}.

  2. 展开 letters 变量,查看其属性,其中包括变量包含的所有元素。Expand the letters variable to see its properties, which include all the elements that the variable contains.

  3. 接下来,将鼠标悬停在 name 变量上,会看到其当前值为空字符串。Next, hover over the name variable, and you see its current value, an empty string.

  4. 多按几次 F5(或“调试” > “继续”),通过 for 循环执行多次循环访问,再次在断点处暂停,每次都将鼠标悬停在 name 变量上以检查其值 。Press F5 (or Debug > Continue) a few times to iterate several times through the for loop, pausing again at the breakpoint, and hovering over the name variable each time to check its value.

    查看数据提示View a data tip

    变量的值随 for 循环的每次迭代而更改,显示的值依次为 ffrfre,依此类推。The value of the variable changes with each iteration of the for loop, showing values of f, then fr, then fre, and so on.

    通常情况下,在调试时,需要快速检查变量的属性值,以查看它们是否存储了你希望它们存储的值,可根据数据提示执行此操作。Often, when debugging, you want a quick way to check property values on variables, to see whether they are storing the values that you expect them to store, and the data tips are a good way to do it.

使用“自动”和“局部变量”窗口检查变量Inspect variables with the Autos and Locals windows

  1. 查看代码编辑器底部的“自动”窗口 。Look at the Autos window at the bottom of the code editor.

    如果已关闭,请依次选择“调试” > “Windows” > “自动”,在调试器中暂停时将其打开 。If it is closed, open it while paused in the debugger by choosing Debug > Windows > Autos.

    在“自动”窗口中,可看到变量及其当前值 。In the Autos window, you see variables and their current value. “自动”窗口显示当前行或前一行使用的所有变量(检查文档中特定于语言的行为) 。The Autos window shows all variables used on the current line or the preceding line (Check documentation for language-specific behavior).

  2. 接下来,我们来看看“自动”窗口旁边的选项卡中的“局部变量”窗口 。Next, look at the Locals window, in a tab next to the Autos window.

  3. 展开 letters 变量以显示其包含的元素。Expand the letters variable to show the elements that it contains.

    检查局部变量窗口中的变量Inspect variables in the Locals Window

    “局部变量”窗口显示当前作用域中的变量,即当前执行上下文 。The Locals window shows you the variables that are in the current scope, that is, the current execution context.

设置监视Set a watch

  1. 在主代码编辑器窗口中,右键单击 name 变量,然后选择“添加监视” 。In the main code editor window, right-click the name variable and choose Add Watch.

    “监视”窗口将在代码编辑器的底部打开 。The Watch window opens at the bottom of the code editor. 可使用“监视”窗口指定要关注的变量(或表达式) 。You can use a Watch window to specify a variable (or an expression) that you want to keep an eye on.

    现在,你在 name 变量上设置好了监视,当你在调试器中移动时,可看到其值发生变化。Now, you have a watch set on the name variable, and you can see its value change as you move through the debugger. 与其他变量窗口不同,“监视”窗口始终显示你正在监视的变量(当超出作用域时,它们会变灰) 。Unlike the other variable windows, the Watch window always shows the variables that you are watching (they're grayed out when out of scope).

检查调用堆栈Examine the call stack

  1. for 循环中暂停时,单击“调用堆栈”窗口,默认情况下,该窗口在右下方窗格中打开 。While paused in the for loop, click the Call Stack window, which is by default open in the lower right pane.

    如果已关闭,请依次选择“调试” > “Windows” > “调用堆栈”,在调试器中暂停时将其打开 。If it is closed, open it while paused in the debugger by choosing Debug > Windows > Call Stack.

  2. 单击多次 F11,直至看到调试器在 SendMessage 方法中暂停 。Click F11 a few times until you see the debugger pause in the SendMessage method. 查看“调用堆栈”窗口 。Look at the Call Stack window.

    检查调用堆栈Examine the call stack

    “调用堆栈”窗口显示方法和函数被调用的顺序 。The Call Stack window shows the order in which methods and functions are getting called. 最上面一行显示当前函数(此应用中的 SendMessage 方法)。The top line shows the current function (the SendMessage method in this app). 第二行显示 SendMessage 是从 main 方法调用的,依此类推。The second line shows that SendMessage was called from the main method, and so on.

    备注

    “调用堆栈”窗口类似于某些 IDE(如 Eclipse)中的调试透视图 。The Call Stack window is similar to the Debug perspective in some IDEs like Eclipse.

    调用堆栈是检查和理解应用执行流的好方法。The call stack is a good way to examine and understand the execution flow of an app.

    可双击代码行来查看该源代码,这也会更改调试器正在检查的当前作用域。You can double-click a line of code to go look at that source code and that also changes the current scope being inspected by the debugger. 此操作不会使调试器前进。This action does not advance the debugger.

    还可使用“调用堆栈”窗口中的右键单击菜单执行其他操作 。You can also use right-click menus from the Call Stack window to do other things. 例如,你可将断点插入到指定的函数中,使用“运行到光标处”推进调试器,然后检查源代码 。For example, you can insert breakpoints into specified functions, advance the debugger using Run to Cursor, and go examine source code. 有关详细信息,请参阅如何:检查调用堆栈For more information, see How to: Examine the Call Stack.

更改执行流Change the execution flow

  1. 按两次 F11 以运行 std::wcout 函数 。Press F11 twice to run the std::wcout function.

  2. SendMessage 方法调用中暂停调试器后,使用鼠标抓住左侧的黄色箭头(执行指针),将黄色箭头向上移动一行,返回到 std::wcoutWith the debugger paused in the SendMessage method call, use the mouse to grab the yellow arrow (the execution pointer) on the left and move the yellow arrow up one line, back to std::wcout.

  3. 按下 F11 。Press F11.

    调试器将重新运行 std::wcout 函数(你会在控制台窗口输出中看到)。The debugger reruns the std::wcout function (you see this in the console window output).

    通过更改执行流,你可以进行测试不同代码执行路径或重新运行代码等操作,而无需重启调试器。By changing the execution flow, you can do things like test different code execution paths or rerun code without restarting the debugger.

    警告

    通常你需要小心使用此功能,工具提示中会出现警告。Often you need to be careful with this feature, and you see a warning in the tooltip. 你也可能会看到其他警告。You may see other warnings, too. 移动指针无法将应用程序还原到更早的应用状态。Moving the pointer cannot revert your application to an earlier app state.

  4. 按 F5 继续运行应用 。Press F5 to continue running the app.

    恭喜你完成本教程!Congratulations on completing this tutorial!

后续步骤Next steps

在本教程中,你已了解了如何启动调试器、逐步执行代码以及检查变量。In this tutorial, you've learned how to start the debugger, step through code, and inspect variables. 你可能会希望更深入地了解调试器功能以及查看指向更多信息的链接。You may want to get a high-level look at debugger features along with links to more information.