在本教程中,将使用 Visual Studio 调试器调试C++应用程序。 调试应用程序时,通常会使用附加的调试器运行应用。 调试器提供了许多方法来检查程序执行过程中的代码正在执行的操作。 可以单步执行代码并查看变量中存储的值,并设置对变量的监视,以查看值何时发生更改。 调试器可帮助你检查代码的执行路径,并确认代码分支正在运行。
在本教程中,你将:
- 启动调试器并在断点处暂停
- 了解在调试器中逐步执行代码的命令
- 检查数据提示和调试器窗口中的变量
- 检查调用堆栈
- 为应用程序设置命令行参数
如果你不熟悉调试,建议在开始本教程之前阅读 对绝对初学者的调试。 如果想要更高级别的调试器功能视图,请参阅 首先查看调试器。
先决条件
安装了使用 C++ 的桌面开发工作负荷的 Visual Studio 2022 版本 17.12 或更高版本。
- 若要免费安装 Visual Studio,请转到 Visual Studio 下载 页。
- 若要免费安装 Visual Studio,请转到 发布和生成历史记录 页了解详细信息。
如果已有 Visual Studio,则可以从交互式开发环境(IDE)中安装工作负荷:
- 选择“工具”>“获取工具和功能”。
- 在 Visual Studio 安装程序中,选择 工作负载 选项卡。
- 选择“使用 C++ 的桌面开发”工作负荷,然后选择“修改”。
- 按照提示操作并完成安装。
本教程使用C++演示应用程序和显示C++语法的屏幕截图。 大多数演示的功能也适用于 Visual Studio 支持的 C#、Visual Basic、F#、Python、JavaScript 和其他语言。 请记住一些限制:
- F#:不支持“编辑并继续”功能。
- F# 和 JavaScript:不支持“自动”窗口。
创建项目
按照以下步骤在 Visual Studio 中创建C++控制台应用程序项目。 项目类型提供快速启动所需的所有模板文件:
在 Visual Studio “开始”窗口中(文件>开始窗口),选择 创建新项目:
将 语言 筛选器设置为 C++,并将 平台 筛选器设置为 Windows。
在“搜索”框中,输入控制台,然后在结果列表中选择控制台应用 模板。
注意
如果未看到 控制台应用 模板,可以从 创建新项目 窗口安装它。 找到搜索结果后面的“找不到要查找的内容?”部分,然后选择“安装更多工具和功能”。 在 Visual Studio 安装程序中,选择具有C++工作负载的 桌面开发并更新安装。 有关详细信息,请参阅 先决条件 部分。
选择 “下一步” 以继续到配置页。
输入
get-started-debugging为新应用的项目名称和解决方案名称。 选择默认“位置”或浏览到环境中的其他路径。选择“创建”以创建新的 Node.js 项目。
Visual Studio 创建了您的新项目,并在 解决方案资源管理器中打开您的项目层次结构。 该文件 get-started-debugging.cpp 在代码编辑器中打开。
创建应用程序
通过在代码编辑器中编辑 get-started-debugging.cpp 文件,为项目创建新应用程序。
将模板提供的默认内容替换为以下代码:
#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;
}
启动调试器
现在,你已准备好开始调试更新的代码:
选择 F5 或“调试”>“启动调试”,启动调试会话。 还可以在“调试”工具栏中选择 “开始调试”
(实心绿色箭头图标)。F5 键盘快捷方式使用附加到应用进程的调试器启动应用程序,但代码中尚没有任何特殊检查内容。 应用只需加载并看到控制台输出:
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本教程稍后将在调试器中更仔细地查看此应用,并浏览其他调试功能。
在调试工具栏中选择“停止”
(红色方块图标)来停止调试器。 还可以使用 Shift + F5 键盘快捷方式。在正在运行的应用程序的控制台窗口中,选择任意键,然后选择 Enter 关闭窗口。
设置断点并启动调试器
尝试在调试器中的选定点设置断点并暂停:
返回到
get-started-debugging.cpp代码编辑器中的文件,并找到for函数的main循环:for (int i = 0; i < letters.size(); i++) { name += letters[i]; a[i] = i + 1; SendMessage(name, a[i]); }若要为包含代码语句
name += letters[i];的代码行设置断点,请在该行代码左侧槽中单击。 Visual Studio 会在该区域中添加一个红色圆圈
来表示设置的断点。提示
还可以将光标放在代码行上,然后选择 F9 切换该行的断点。
断点是可靠调试的最基本和最重要功能之一。 断点指示你想让 Visual Studio 在哪个位置挂起你的运行代码。 暂停执行时,可以查看变量的值、检查内存的行为,或检查代码分支是否正在运行。
选择 F5 或“开始调试”,在调试器中启动应用。
Visual Studio 开始执行您的应用程序。 当调试器到达设置断点时,调试进程将暂停。
Visual Studio 向边栏中的红色断点圆添加黄色箭头,以表示调试器暂停所在的代码语句。 程序执行已暂停,指示的语句正在等待处理。
注意
F5 操作与应用程序当前的执行状态相关。 如果你的应用未运行,并且你选择 F5,调试器将启动你的应用并继续执行,直到它到达第一个设置断点。 此行为映射到“调试”>“开始调试”命令。 如果你的应用已在运行,并且你选择 F5,应用执行将继续,直到调试器到达下一个断点或程序结束。 此行为映射到“调试”>“继续” 命令。
当您知道要详细检查的代码行或部分代码时,断点是一项有用的功能。 有关可以设置的不同类型的断点的信息,例如条件断点,请参阅 使用正确的断点类型。
在调试器中逐步执行代码
在调试器中浏览代码的一种便捷方法是使用 步骤命令。 这些命令允许你 进入、跳过和 跳出代码段,并在应用执行中 后退。
以下过程重点介绍了如何使用键盘快捷方式和步骤命令快速完成代码。 (等效的菜单操作显示在括号中。
选择 F5 或“开始调试”,在调试器中启动应用。
当调试器在
for函数的main循环中暂停时,按 两次>(“调试”“单步执行”)以跳转到SendMessage方法调用。按两次 F11 后,执行将继续到代码语句
SendMessage(name, a[i]);。再次选择 F11 以进入
SendMessage方法。请注意,黄色指针会前进到
SendMessage方法:
F11 键盘快捷方式会启动“单步执行”命令,让应用一次执行一条语句。 这是一种详细检查执行流的好方法。 默认情况下,调试器跳过非用户代码。 有关详细信息,请参阅仅我的代码。 在本教程的后续部分,您将学习如何更有效地浏览代码。
检查
SendMessage方法后,可以使用 Step Out 命令继续调试。 选择 Shift + F11(“调试”>“单步跳出”)。此命令将恢复应用执行(并推进调试器),直到当前方法或函数返回。
命令完成后,调试器会暂停在
for方法内main循环中的SendMessage方法调用处。多次选择 、F11 和,直到再次返回到
SendMessage方法调用。调试器暂停在方法调用处时,请选择 F10(“调试”>“单步跳过”)。
请注意这一次,调试器这次没有进入
SendMessage方法。 F10 快捷方式会推进调试器,而无需单步执行应用代码中的函数或方法(代码仍执行)。 如果在 方法调用处选择SendMessage(而不是 F11),则会单步跳过SendMessage的实现代码。 此方法可用于跳过暂时不需要检查的代码。 有关在代码中进行移动的不同方法的详细信息,请参阅浏览调试器中的代码。
通过“运行时单击”浏览代码
在调试器中执行代码的另一种方法是使用“运行时单击”功能。 此操作类似于设置临时断点。
继续调试会话:
选择 F5 以前进到代码中的断点。
在代码编辑器中,滚动到
SendMessage方法定义,并将鼠标悬停在std::wcout函数上。将鼠标悬停在代码语句上,直到代码语句左侧出现“运行时单击”
(绿色箭头图标)。 如果将鼠标悬停在图标上,则会看到工具提示“运行到此处”:
选择“运行时单击”
。调试器将执行推进到指示的位置。 在此示例中,调试器到达对
std::wcout函数的调用。
“运行时单击”操作对于快速到达应用代码的可见区域也很方便。 可以在代码编辑器中打开的任何文件中使用该功能。
快速重启应用
通过在调试工具栏中选择 “重启
(圆形箭头图标)来快速重启应用。 还可以选择 “调试”> 重启 或使用 ctrl Ctrl + Shift + F5 键盘快捷方式。
重启 功能比停止应用并再次启动调试器更有效。
选择 重启时,调试器会在执行过程中遇到的第一个断点处暂停。 在此示例中,调试器会在在 for 循环中设置的断点处再次停止。
使用数据提示检查变量
有助于检查变量的功能是使用调试器的最有用优势之一。 通常,在调试问题时,你正尝试发现变量是否在特定时间存储预期值。 Visual Studio 提供了多种方法来帮助你完成此任务。
继续调试会话:
在
name += letters[i]语句上暂停调试器时,将鼠标悬停在letters变量上。 选择变量名称左侧的展开/折叠箭头,并在浮出控件菜单中查看其属性。数据提示 功能显示变量包含的所有元素。 请注意默认值,
size={10}:
接下来,将鼠标悬停在
name变量上,并注意到其当前值(空字符串("")。多次选择 F5(“调试”>“继续”),以便通过
for循环执行多次循环访问。 每次调试器暂停断点时,将鼠标悬停在name变量上并检查当前值:
变量的值随
for循环的每个迭代而更改,其中显示了f、fr、fre等值。
使用“自动”和“局部变量”窗口检查变量
另一种检查变量和值的方法是使用 自动窗口 和 局部变量窗口。 默认情况下,在调试应用时,这些窗口显示在 Visual Studio IDE 中的代码编辑器下方:
请注意代码编辑器下方的“Autos”窗口。
如果在调试会话期间看不到该窗口,请选择调试>Windows>Autos 来打开窗口。
“自动”窗口显示当前行或上一行上使用的所有变量及其当前值。 请记住,特定的编程语言可以演示变量和属性的唯一行为。 有关详细信息,请参阅 Visual Studio 语言指南。
接下来,查看“局部变量”窗口。 默认情况下,此窗口与 Autos 窗口对齐。
如果在调试会话期间未看到窗口,请选择 调试>Windows>局部变量,以打开窗口。
在 局部变量 窗口中,展开
letters变量以显示其包含的元素。
局部变量 窗口显示当前 作用域(即当前执行上下文)中的变量。
监视变量
如果你想监视特定变量的行为,可以设置一个监视:
在代码编辑器中,右键单击 name 变量,然后选择“添加监视”。 随即会在代码编辑器下方打开“监视”窗口。 可以使用 监视 窗口指定要跟踪的变量(或表达式)。
在调试器中的应用执行期间观看 name 变量时,可以看到其值更改。 与其他变量窗口不同,监视 窗口始终显示正在监视的变量。 当监视的变量不在范围内时,变量名称将灰显。
检查调用堆栈
Visual Studio 中的 调用堆栈 窗口显示调用方法和函数的顺序。 此窗口类似于 Eclipse 之类的某些 IDE 中的“调试”透视。 默认情况下,在代码编辑器下面的调试会话中,调用堆栈在右下窗格中可见。
当调试器在
for循环中暂停时,请选择 调用堆栈 窗口以查看当前调用结构。如果在调试会话期间看不到该窗口,请选择调试>窗口>调用堆栈打开该窗口。
按 F11(“调试”>“单步执行”)几次,直至看到调试器在
SendMessage方法中暂停。再次查看 调用堆栈 窗口:
在 调用堆栈 窗口中,上行显示当前函数(此应用中的
SendMessage方法)。 第二行显示SendMessage方法是从main方法调用的,依此类推。
调用堆栈是检查和了解应用执行流的好方法:
- 双击代码行以浏览到源代码。 此操作还会更改调试器正在检查的当前范围,但它不会推进调试器。
- 访问 调用堆栈 窗口中编程元素的右键单击菜单。 例如,可将断点插入到指定的函数中、使用“运行到光标处”使调试器前进,以及浏览到源代码。 有关详细信息,请参阅 查看调用堆栈并使用调试器中的“调用堆栈”窗口。
更改执行流
另一项功能强大的调试器功能是能够在调试期间修改执行流:
按两次 F11(“调试”>“单步执行”)以运行
std::wcout函数。调试器在
SendMessage方法调用中暂停时,选择黄色箭头(执行指针)并将其拖动到变量左侧,并将箭头移动到上一个代码语句,std::wcout。再次选择 F11。
调试器重新运行
std::wcout函数。 可以在终端输出中跟踪进程。通过更改执行流,可以执行诸如测试不同代码执行路径或重新运行代码之类的操作,而无需重启调试器。
谨慎
使用此功能时请仔细注意。 选择黄色箭头时,Visual Studio 会在工具提示中显示警告,指示执行更改可能会产生意外后果。 可能还会看到其他警告,具体取决于你的方案。 请记住,移动指针无法将应用程序还原到以前的应用状态。
选择 F5 以完成应用执行。
传递命令行参数
在项目属性中为应用程序设置命令行参数。 如果要测试应用使用不同命令行参数的行为方式,这非常有用。
从 Visual Studio 2026 开始,可以在命令行参数工具栏下拉列表中为应用程序设置命令行参数。 此功能适用于 Visual Studio C++ 项目、Unreal Engine .uproject 项目和 CMake 项目。 它目前处于预览状态,在最终发布之前可能会更改。
通过将文件中的代码 get-started-debugging.cpp 替换为以下内容,修改应用程序以接受命令行参数:
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
void SendMessage(const std::wstring& name, int msg)
{
std::wcout << L"Hello, " << name << L"! Count to " << msg << std::endl;
}
int main(int argc, char* argv[])
{
// Detect if the /u command-line argument was passed to the application.
bool uppercase = false;
for (int i = 1; i < argc; ++i)
{
if (std::string(argv[i]) == "/u")
{
uppercase = true;
break;
}
}
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;
std::wstring nameToSend = name;
if (uppercase) // Convert the name to uppercase if the /u argument was passed.
{
std::transform(nameToSend.begin(), nameToSend.end(), nameToSend.begin(), ::towupper);
}
SendMessage(nameToSend, a[i]);
}
return 0;
}
此更新版本的应用程序接受命令行参数,该参数 /u 在输出之前将名称转换为大写。
若要在开始调试命令行参数时将命令行参数传递给 /u 应用程序,请执行以下步骤:
在 “标准 ”工具栏中, 命令行参数 文本框,键入
/u:
在第 19 行上放置断点,
uppercase = true;方法是单击该行上的左侧装订线。
选择“开始调试”按钮或按 F5开始调试应用程序。
调试器命中断点,因为
/u作为命令行参数传递:
选择 F5 以继续运行应用程序。 控制台窗口中的输出现在以大写形式显示名称:
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
命令行参数将按照输入它们的顺序保存在下拉列表中,并显示在下拉列表中以供将来使用。 在删除最早的命令行以腾出新命令行之前,可以添加五个命令行。
可以选择下拉列表箭头以查看以前使用的命令行参数的列表。
在不同的项目类型中传递命令行参数
命令行参数下拉列表包含项目类型特定的选项,用于打开调试器传递给程序的参数的经典方法。 对于 .vcxproj 项目,它通过项目设置属性页。 对于 CMake 项目,它通过编辑 vs.launch.json 文件。 对于 Unreal Engine 项目,它通过编辑 .uproject 文件。
Visual Studio 项目类型 (.vcxproj)
在 Visual Studio 项目中(.vcxproj),命令行参数下拉列表中会显示一个选项,用于 在属性页中编辑:
选择“ 属性页中的编辑 ”,打开“ 调试 ”属性页的项目属性窗口,可在其中设置命令行参数以在调试应用程序时传递:
命令 参数 的更改反映在命令行参数下拉列表中,供将来调试会话使用。
CMake 项目类型
对于 CMake 项目,命令行参数下拉列表中会显示一个选项,用于编辑:launch.vs.json
选择 “编辑” launch.vs.json,打开 launch.vs.json 文件并设置命令行参数,以在元素中 "args" 调试应用程序时传递:
对文件的更改反映在命令行参数下拉列表中,供将来调试会话使用。
Unreal Engine 项目类型 (.uproject)
对于 Unreal Engine 项目,命令行参数下拉列表中会显示一个选项,用于编辑:UETargetProperties.json
选择 “编辑” UETargetProperties.json,打开 UETargetProperties.json 在“args”元素中调试应用程序时要传递的命令行参数的文件:
对文件的更改反映在命令行参数下拉列表中,供将来调试会话使用。