好像这个应该在 2018 年就写的……
最近有不少大一小朋友们又开始了饱受 Dev C++ 折磨的 C 语言课程。有一部分先进的小朋友选择使用 Visual Studio 进行编程,不过还是在 scanf 和 scanf_s 之间挣扎了一段时间。如果是纯粹为了 C 语言上机题,完全没必要大动干戈使用完整的 VS(至于 Dev C++?赶紧把这玩意儿丢进历史的垃圾堆吧),可以选择相对轻量的 Visual Studio Code。
其实我自己是在 2018 年大一的时候就已经开始在用 VSCode 了。不过最近有小朋友们问到了这个事情,就开一篇博客写一些吧(毕竟最近也没什么写的)。
话不多说,行くぞ!
先决条件
本文旨在讨论 Windows 环境下配置 VSCode 的开发环境,因此当然要先装好 VSCode 啦。
编译器的选择上,本文采用 TDM-GCC。选择它的原因是因为 64 位的 TDM-GCC 可以选择编译出 32 位还是 64 位的可执行文件,同时它的版本相对来说还算新的。在官网上下载时注意选择 64+32-bit 版本的。
如果追求更新的 GCC 版本,可以考虑使用 msys2。另外,极其不建议使用 MinGW-w64,它的 GCC 相对来说较旧(最后一个版本只到 8.1.0),而 8.1.0 又存在一个严重的 Bug。
编译器安装的时候,注意勾选添加 PATH 环境变量。完成之后,打开命令行界面,键入 gcc --version 然后回车。如果环境变量正确配置,将会看到如下图所示的输出。

安装好 VSCode 和编译器之后,我们开始进行配置。
配置 VSCode
VSCode 的开发配置是基于文件夹的,因此选择一个你喜欢的位置作为日后 C/C++ 单文件开发的项目文件夹,然后在 VSCode 中打开这个文件夹(如果在安装 VSCode 的时候注册了右键菜单,可以右击然后选择“通过 Code 打开”)。最新的 VSCode 会提示安全问题,选择“是,我信任此作者”。

然后我们新建一个 C 或者 C++ 源代码文件,并编写任意一段合法代码。习惯起见,下面我一律以 C++ 为例。
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout << "Hello World!" << endl;
return 0;
}
编写完成之后,保存它。这个时候 VSCode 应该会提示你安装 C/C++ 语言开发插件,我们按照提示完成插件的安装。
插件安装完成之后,VSCode 会需要进行设置以配置 IntelliSense。最新版本的 VSCode 已经提供了图形化的界面,相比以前手动编写 JSON 会方便很多。点击“配置(UI)”。

在“编译器路径”一项中,正常情况下 VSCode 应该会检测到我们先前安装的 TDM-GCC,直接从下拉列表里选择即可。如果没有列出,那么就需要手动填写编译器安装目录下 bin 文件夹内编译器可执行文件的完整路径。关于选择 gcc 还是 g++,这里建议选择 g++。因为 G++ 编译 C 语言源代码文件比 GCC 编译 C++ 语言源代码文件会方便一些。

“编译器参数”部分,一般情况下我们需要的操作就是编译并输出可执行文件,因此填入下列内容即可,如后图所示。-std=c++17 可以不填,我这里只是比较喜欢用新一点的标准罢了。
-g
-std=c++17
${file}
-o
${fileDirname}\\${fileBasenameNoExtension}.exe

“IntelliSense 模式”选择 windows-gcc-x64。
“包含路径”填写下列内容。注意根据自己安装的编译器路径进行调整。
${workspaceFolder}/**
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/10.3.0/include/c++/x86_64-w64-mingw32
C:/TDM-GCC-64/x86_64-w64-mingw32/include
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/10.3.0/include
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/10.3.0/include/c++/backward

“C 标准”根据喜好选择 c11 或者 c17。“C++ 标准”根据选择喜好选择 c++11 或者 c++17,注意这里和上面的 -std=c++17 保持一致。GCC 10.3.0 对于 c++20 的支持似乎不太好,想选的话应该也行。

完成配置之后关掉设置选项卡,返回源代码。如果一切配置妥当,这时候应该所有红线都消失了,并且按下 Shift + Alt + F 能够正确格式化代码。
按下 F5,会弹出调试配置选择,这里我们选择“C++ (Windows)”。

然后会提示正在下载依赖,耐心等待。不过比较诡异的是下载的是 C# 的依赖,我也不知道为什么。

接下来生成调试配置文件,选择“默认配置”。

这个时候会打开 .launch.json 文件。将原有的 configuration 数组的内容删除,点击右下角的“添加配置...”,选择“C/C++:(gdb) 启动”。这个时候配置文件应该会变成下图所示的样子。

我们需要修改 program 和 miDebuggerPath。miDebuggerPath 需要根据先前安装的编译器路径进行调整,使之指向 GDB 的可执行文件。修改后的文件内容如下。
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) 启动",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:/TDM-GCC-64/bin/gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
保存文件。点击“终端”→“配置默认生成任务...”,选择“C/C++:g++exe 生成活动文件”。

插件会根据我们之前填写的配置自动生成 tasks.json 文件,如图。

这里 args 数组的值有点问题需要修改,修改后的整个文件内容如下。
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件",
"command": "C:/TDM-GCC-64/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"-std=c++17",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "C:/TDM-GCC-64/bin"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "编译器: C:/TDM-GCC-64/bin/g++.exe"
}
]
}
对于初学者,可以酌情增加 -Wall 参数以帮助快速发现代码中的潜在问题。修改完毕之后保存。再次打开 launch.json 文件。向 configurations 数组里刚才配置好的项目加入 "preLaunchTask": "C/C++: g++.exe 生成活动文件",如下所示。这里的值对应了 tasks.json 里 tasks 数组配置好的项目中 label 的值。
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) 启动",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:/TDM-GCC-64/bin/gdb.exe",
"preLaunchTask": "C/C++: g++.exe 生成活动文件",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
保存文件。返回到前面创建的 C/C++ 源代码文件。按下 F5,这时候会开始编译生成可执行文件并启动调试。在“调试控制台”选项卡中可以执行 GDB 命令,在“终端”选项卡中可以对程序进行输入输出。本文的例子中可以看到输出的 Hello World! 字样。

至此 VSCode 的配置即告完成。
使用 VSCode 进行断点调试
VSCode 的调试某种程度上来说师出 VS,比 Dev C++ 高到不知道哪里去了。下面来简单讲解一下如何进行断点调试。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a;
cin >> a;
for (int i = 0; i < 10; i++)
{
a++;
}
cout << a << endl;
return 0;
}
鼠标放在行号上,在行号的左边会出现一个小红点,点击它就成功在这一行打上了断点。我们在第 11 行 a++ 下断点。

按下 F5。前面提到在“终端”选项卡中可以进行输入输出。这里我们输入 1 作为 a 的初值。
回车之后会发现程序暂停执行了,同时第 11 行被高亮标注起来,表明当前程序暂停到了第 11 行之前的位置。需要注意的是,高亮行的代码在断点的时候还尚未执行。因此这时候 a 的值仍旧是 1。

在左侧的“变量”窗格中,可以看到当前作用域内所有局部变量的值。如果有全局变量,也会在这里显示出来。Registers 中列出了所有寄存器的值。“监视”窗格中可以根据自己的需要,设定一些要关注的表达式的值。“调用堆栈”窗格中展示了当前断点处的调用堆栈,这个功能在分析多个函数嵌套调用时很有帮助。“断点”窗格中显示了当前文件中所有的断点,点击前面的复选框可以临时禁用或启用一个断点,在这里也可以批量禁用或者启用所有断点,还可以直接删除所有的断点。
如果想删除已经打过的断点,可以再次点击行号前的小红点使它消失。

按下 F5 或者 F9 可以继续执行,如果在后面的执行中遇到断点,VSCode 会再次暂停,直到没有断点或程序退出。
完
Windows 下 VSCode 的单文件 C/C++ 配置大致就是这样。这一套足够应付所有涉及到 OJ 的单文件编程了。初学编程,还是要打好基础,养成好习惯。
怪,为啥只有大于号没有转义
xmgg,断点调试的代码块处有误:< 被识别成了 < 。(闲的没事233,我不会说是我直接复制报错发现的(ó﹏ò。)ノ