1. 预备知识

由于VSCode本质上是个高级记事本,因此配置它需要一些前置知识。

1.1 源代码和编译

源代码文件是存放代码的文本文件,C代码文件的后缀名一般为.c,C++代码文件的后缀名一般为.cpp,头文件的后缀名一般为.h,它们都是文本文件(所以可以用记事本打开编辑)。

文本文件是不能运行的,所以我们需要把写好的代码翻译成机器能够执行的形式,这个过程就被称为编译。用来编译代码生成可执行文件的程序被称为编译器,目前主流的C/C++编译器有MSVC(cl.exe)、GCC(gcc/g++)和LLVM(clang/clang++)

准确地说源代码文件要变成可执行文件需要进行预处理编译汇编链接等步骤,可以参阅这篇文章

1.2 命令行和环境变量

命令行界面就是科幻电影中常见的那种全是字符的界面,我们通过输入一些命令来执行操作。

windows上自带的cmd和powershell就是命令行界面,可以按Win+R输入cmdpowershell来启动它们。启动后会有一串字符提示你现在在哪个路径下,我们可以通过cd命令来切换当前所在的路径。

小技巧:在文件管理器按F4会跳到路径栏,输入cmd并回车即可在此文件夹打开cmd(不用再cd了)。

  • 不知为何windows自带的powershell不能这么打开
  • win11的用户可以直接右键在当前路径打开Windows Terminal

1.2.1 在命令行界面运行程序

只要输入一个程序的相对路径或者绝对路径,就能够运行那个程序(可以不用写.exe

以powershell启动steam为例:

  1. # powershell启动steam
  2. cd E:\steam_main # 首先cd到steam.exe所在的文件夹
  3. .\steam
  4. # 或者直接使用绝对路径
  5. E:\steam_main\steam

powershell需要./<名字>或者.\<名字>来运行当前路径下的程序,但cmd应直接输入<名字>

1.2.2 path变量

每次都需要输入程序的路径当然相当麻烦,有没有办法简化一点?

答案就是利用path变量

path变量顾名思义,其中存放了一系列的路径。当你在命令行输入的程序不在当前目录下时,系统就会依次去这些路径里找有没有名字一样的程序。所以只要我们把程序的路径加入到path变量,就可以在任意路径下运行它啦。

例如:将E:\steam_main添加到path变量中后,就可以在任意路径下输入steam来启动steam

1.2.3 修改path变量

Win+S搜索path,选择修改系统环境变量,点开环境变量,然后在用户变量(只对当前用户起效)或者系统变量(对所有用户起效)中找到path变量,双击修改即可。

  • Windows的环境变量有2047字符的最大长度限制,所以不要随便什么东西都往path变量塞
  • 顺便一提,windows单个路径的长度也有260字符的限制(不要问我是怎么发现这一条和上一条的

1.3 编辑器和IDE

编辑器指的是用来编辑源代码文件(文本文件)的程序,windows自带的记事本就是一种编辑器。编辑器可以提供代码高亮、补全等功能,但本身并不负责把代码编译成可执行文件,所以需要和编译器搭配使用。

集成开发环境IDE),是把编辑器、编译器和其它组件整合到一起的一整套程序。可以直接用它编写代码、编译、调试程序等等,但一般需要你先建一个工程。例如Dev-C++就是经典的C++ IDE.

VSCode是一种编辑器,因此需要我们另外下载编译器来编译代码,并且通过一些设置使VSCode能方便地调用编译器并运行编译出来的程序。

所以我们需要做的就是:

  • 下载安装C/C++编译器
  • 下载安装VSCode
  • 设置VSCode

2. 下载安装编译器

首先要下载一个编译器用来编译我们的代码。

本文使用GCC作为编译器,在windows系统上,推荐通过MSYS2来安装它。

2.1 MinGW/MinGW-w64

如果自己搜索过如何在windows上安装gcc的话,一定听说过MinGW。GCC本身是Linux上的编译器套件,不能在windows上运行,而mingw则是gcc在windows上的移植。

最早的mingw项目只支持编译32位程序,后来分支出的mingw-w64项目则同时支持编译32/64位程序。

网上其它教程的mingw一般都来源于MinGW原项目(gcc版本9.2.0-2,只能编译32位程序),或者MinGW-w64的SourceForge(以前可执行文件会放在这上面,但是现在只更新源代码,所以gcc版本停留在8.1.0),版本都相对比较古旧,不推荐到这两处地方下载mingw

mingw-w64项目目前的状况比较复杂,有多个发行分支,具体可以参看官网的下载页。目前windows上最新、最靠谱的发行分支就是MSYS2(gcc版本12.1.0-2)。

关于mingw和mingw-w64的渊源,可以看这篇科普

2.2 MSYS2

MSYS2(Minimal SYStem 2)是与mingw-w64配套的命令行环境,它为windows提供了类似linux的命令和包管理器pacman,可以直接在命令行查找、安装和卸载各种第三方库和开发工具。

  1. # 比如你想要安装opencv库
  2. pacman -Syy mingw-w64-x86_64-opencv
  • pacman同时是ArchLinux的包管理器(就像MacOS上的homebrew和Ubuntu上的apt一样),具体使用办法可以查阅ArchWiki(中文)
  • 实际上MinGW也有一个配套的MSYS,但它没有包管理器
  • git bash实际上是一个删减版的MSYS2,在安装文件夹下可以看到MSYS2的目录结构,但它也没有包管理

2.3 安装MSYS2和mingw编译器

2.3.1 下载安装MSYS2

安装MSYS2很简单,前往MSYS2官网下载安装程序即可。安装过程就是选安装位置,然后一直点下一步,没有什么需要特别注意的地方。

VSCode + MSYS2搭建C/C++开发环境 - 图1

点击图中所示位置下载MSYS2

2.3.2 MSYS2的子环境(选读)

MSYS2实际上是由6个独立的子环境组成的。每个子环境会有一个单独的文件夹,和一个专门的命令行界面入口,具体区别见下图。一般来说,直接使用UCRT64就行。

VSCode + MSYS2搭建C/C++开发环境 - 图2

MSYS2包含的几个子环境

打开MSYS2的安装目录,可以看到这些子环境的位置。刚安装好MSYS2的话,除了usr文件夹以外,其它的子环境文件夹里应该还都是空的。

VSCode + MSYS2搭建C/C++开发环境 - 图3

MSYS2的安装目录结构

一般来说,每个子环境下都有bin(含编译器的可执行文件等)/include(标准库和安装的第三方库头文件)/lib(动态库和静态库等)等文件夹,如果遇到问题可以去相应的路径查看。

详细解释一下几个子环境的区别:

  • MSYS环境是基础环境,包含各种linux命令行工具(例如pacman等),其它子环境都继承于它。但在这个子环境里编译的程序依赖于MSYS2的动态库,因此直接把编译出来的.exe发给其他人的话会无法运行,需要带上/usr/bin文件夹下的MSYS-2.0.dll等依赖库才行。一般不建议使用。(需要完整linux环境的请考虑WSL或者虚拟机)
  • MINGW64环境编译的程序不依赖MSYS2,只依赖于windows自带的C语言库msvcrt,较为通用。
  • UCRT64与MINGW64类似,但依赖于比较新的C语言库ucrt,这个库win10/11自带,也是目前微软家的Visual Studio使用的库,但win7/XP可能需要手动安装。未来将会替代MINGW64。
  • CLANG64环境使用LLVM工具链而非GCC工具链,所有配套环境都是基于LLVM的(比如这个环境里的gcc.exe其实是clang.exe的重命名)。
  • MINGW32和CLANG32顾名思义,使用32位的mingw/clang工具链,如果没有特殊需求基本不用考虑,用64位版本就好。

最早只有MSYS,MINGW64和MINGW32三个子环境,子环境数量由于开发的需要正在增加,将来可能还会加入CLANGARM64(可用于Android程序编译)

2.3.3 使用pacman安装编译器

打开MSYS2命令行,输入pacman -Syu同步更新所有工具,然后输入pacman -S mingw-w64-ucrt-x86_64-toolchain安装mingw-w64工具链。中间出现询问之类的一路回车就好,等待一段时间后应该就安装完毕了。

VSCode + MSYS2搭建C/C++开发环境 - 图4

安装mingw工具链

安装完成后ucrt64/bin文件夹下应该能找到gcc.exe,然后将此路径加入环境变量

如果一切正常,那么打开命令行,输入gcc --version应当能显示gcc的版本,MSYS2目前的gcc版本是12.1.0 Rev2

如果提示找不到gcc或者gcc不是批处理等错误,可以尝试关闭重开powershell/cmd再次尝试,如果仍然失败,那么应当是环境变量没有设置对。

VSCode + MSYS2搭建C/C++开发环境 - 图5

检查gcc版本

如果没有问题,那么我们的编译器就安装成功啦。

2.4 在命令行使用gcc(选读)

事实上,我们现在已经可以写C/C++代码并运行了。例如,新建一个文本文件hello.c,内容如下

  1. #include <stdio.h>
  2. int main(void) {
  3. puts("Hello, world!");
  4. return 0;
  5. }

然后在这个路径下命令行输入gcc hello.c -o hello,就能生成一个hello.exe文件,在命令行运行它就能看到输出。(不要双击运行它,因为运行结束后默认会退出命令行界面,你就看不到输出了!)

VSCode + MSYS2搭建C/C++开发环境 - 图6

命令行编译运行

简单来说,输入gcc <源代码文件> -o <输出程序名字>就可以将C代码文件编译成指定名字的可执行文件。而对于C代码,将gcc换成g就行。

如果你能接受使用Notepad2之类的轻量化编辑器加上手打命令行编译运行的话,也够应付刚入门时的各种单文件小程序了(不过缺点是不能调试)。

而在VSCode(和各种IDE)中,本质上就是将这里这个手动输入命令行的过程自动化了。

详细的gcc使用说明可以参考这个,不过如果英文可以的话建议还是看GNU手册

3. 安装并配置VSCode

3.1 下载安装VSCode

VSCode官网下载安装包,按照提示安装就行。

建议勾选在右键菜单中添加“通过code打开”,方便我们在指定位置打开vscode。

VSCode + MSYS2搭建C/C++开发环境 - 图7

勾选“通过code打开”这两项

3.2 VSCode操作简介

简单介绍一下常用的VSCode操作。

3.2.1 内置命令行

VSCode内置了命令行,按下快捷键`Ctrl+``,就可以调出内置的集成终端以便使用。VSCode默认使用powershell作为终端。

3.2.2 常用快捷键

  • F1/Ctrl+Shift+P:查找运行vscode命令
  • Ctrl+,:打开vscode设置
  • Ctrl+Shift+K:删除整行
  • Alt+上下方向键:移动行
  • Shift+Alt+F:代码格式化
  • 按住Alt用鼠标点选可以选中多处
  • 按住Shift+Alt可以鼠标拖动多选
  • Ctrl+D选中一个单词,Ctrl+L选中一整行

3.3 安装插件

初次进入vscode的话,会是全英文界面,需要安装中文插件来切换到中文,一般来说现在会在右下角弹出来,点击安装就行。

然后打开插件栏,搜索安装C/C和Code Runner插件,用来提供C/C代码高亮和编译运行C/C++代码。

VSCode + MSYS2搭建C/C++开发环境 - 图8

安装插件

打开设置,勾选code runner插件设置中的run in terminal选项,让代码在vscode的集成终端里运行,这样才能在命令行输入。

3.4 受信任文件夹

vscode最近的更新增加了一个信任工作区,每打开一个新的文件夹都会提示你是否信任,这个功能挺麻烦的,可以关掉。

使用Ctrl+,打开设置,搜索“信任”,取消勾选“启用工作区信任”,即可关掉这个功能。

4. 运行与调试C/C++代码

4.1 单文件的运行

对于单个源文件的C/C++代码来说,可以直接使用code runner来运行。只要点击右上角的小三角形,或者使用快捷键Ctrl+Alt+N就能编译运行C语言代码。

其实可以看到,code runner的原理就是自动在命令行输入编译和运行的命令,和我们自己手动输入命令没有区别。

输入的命令也可以在相应的插件设置中进行修改。

VSCode + MSYS2搭建C/C++开发环境 - 图9

使用code runner运行C代码

4.2 单文件的调试

按下F5,依次选择C++(GDB/LLDB)和我们MSYS2环境中的gcc.exe,VSCode会自动生成配置文件,并生成调试。

VSCode + MSYS2搭建C/C++开发环境 - 图10
VSCode + MSYS2搭建C/C++开发环境 - 图11

可以在行号的左边单击来设置断点,程序运行到断点前会自行中断。左侧可以看到此时各个变量的值,监视栏中可以输入表达式观察。

VSCode + MSYS2搭建C/C++开发环境 - 图12

VSCode调试界面

另外,目前VSCode支持了条件断点,只要右键断点,选择编辑断点即可设置中断条件,具体使用方法可以参考VSCode文档

VSCode + MSYS2搭建C/C++开发环境 - 图13

VSCode的条件断点

至此,可以愉快地写代码啦。


下面的内容是一些工具推荐和踩坑经验,留给有一定基础的C/C++初学者

5. 踩坑经验和工具推荐

5.1 多文件编译和调试

读者可能会注意到上一节中我们只提了单文件的运行和调试,没有提到多文件的运行及调试。

这是由于用VSCode多文件编译,不可避免地需要涉及C/C++编译系统的概念,不太适合刚入门的初学者学习,这里给出几种方案和一些参考链接。

简单来说,编译系统要解决的基本问题有两个:一个是哪些文件需要以何种方式被编译到一起,另一个是当某个文件被修改的时候,哪些文件需要被重新编译。这一般需要我们编写配置文件(Makefile, CMakeLists.txt等)来描述各个代码文件间的关系,然后相应的程序可以根据配置文件调用编译器完成编译。

这篇文章以make/automake为例,讲解了编译系统是如何从脚本开始演化为现在的样子的。写的很好,只是作者已经不在知乎了。

5.1.1 Make

Make是最原始的C/C++编译系统,语法简单,是linux原生的多文件编译方案。需要注意的是mingw项目中的make叫做mingw32-make,需要复制一份重命名make.

详细的make指南可以查阅这里

我最初多文件运行/调试使用的就是make,可以调整code runner的命令行来使用make进行编译,调试的话则要自己调整task.json文件。

不建议初学者自己在VSCode上配置makefile工程,比较麻烦。我写了一个VSCode的makefile工程模板放到了Github上,感兴趣的可以查看和使用(有问题也可以直接提交issue)。

5.1.2 CMake+Ninja

当然make已经是相当古老的工具了,如今最为广泛使用的C/C编译系统是CMake。CMake的优点是可以生成其它工具和IDE的配置文件,便于我们编写跨平台、跨IDE的C/C工程。

VSCode对CMake的集成很不错,有微软官方的cmake-tools插件支持,可以不编写launch.jsontask.json直接根据cmake当前的配置进行运行和调试。如果检测到路径中有ninja,则会自动调用ninja加速编译。

在MSYS2中使用pacman -S mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja即可在UCRT64环境中安装cmake+ninja.

可以参考这个仓库cmake Tutorial来学习CMake,必要时可以查阅cmake的官方文档

CMake的官方文档是出了名的烂,强烈不建议直接硬啃文档来学CMake

5.1.3 xmake

总之如果你使用了一段时间cmake,你就会发现cmake用起来总是有各种各样让人不舒服的地方,由国人开发的xmake可能是它的一个更好的替代。

xmake相比cmake更快,集成度更高(集成了包管理和分布式编译等),给我的感觉就像C/C++版本的cargo(rust邪教(不))。而且也支持直接集成使用cmake等其他编译系统的C/C++项目,减少迁移成本。

插件支持方面,vscode上也有xmake的插件支持,能提供和cmake-tools插件类似的功能,总之推荐尝试一下。

唯一的问题就是用的人比较少,而CMake最大的优点就是大家都在用…

一些注意事项:

  • 使用pacman -S mingw-w64-ucrt-x86_64-xmake可在UCRT64环境中安装xmake。不过这样xrepo只能在UCRT64的shell里用,在外面用需要写个wrapper脚本
  • 或者也可使用windows上的包管理器scoop来安装原生的xmake,命令是scoop install xmake,没有上述问题
  • 开始使用前需要用xmake g --mingw=$env:MSYS2\ucrt64设置mingw的路径(如果你用cmd,那么是xmake g --mingw=%MSYS2%\ucrt64
  • 其他设置可以去看xmake官网,并善用浏览器ctrl+f搜索

5.2 第三方库的安装和使用

C/C++最让人头疼的地方之一就是如何安装和使用第三方库了,对新手来说编译一个第三方库的项目基本上是个噩梦,遇到错误往往摸不着头脑。

5.2.1 第三方库的安装

本文选用MSYS2,一个主要的考虑就是为了方便安装第三方库。只需要pacman -Ss搜索一下库的名字,再按搜出来的名字pacman -S安装就行了,大部分常用的第三方库都能找到。头文件安装在子环境名/include,库二进制文件则安装在子环境名/lib下,这两个路径是编译器的默认搜索路径。

  • 如果使用过python,那么可以把pacman理解为类似于pip一样的东西。
  • 需要先pacman -Ss搜索,因为除了MSYS子环境,包名通常会有一个很长的前缀,和库本身的名字并不相同。例如pacman -S cmake安装的是MSYS子环境的cmake,要安装ming64子环境下的cmake,则应该是pacman -S mingw-w64-x86_64-cmake

5.2.2 第三方库的使用

头文件include错误

因为头文件直接装在了默认搜索路径里,所以一般安装完毕后直接#include <...>就可以了。

但是也有例外,比如OpenCV的头文件是在默认路径的一个子文件夹下,是一个独立的include系统,这时候需要为编译器指定-isystem <路径>选项。

undefined reference

这种情况是因为编译器不知道某个库函数的实现在哪。你需要使用gcc的-l选项链接安装的库,比如g++ a.cpp -lfmt就是指定编译a.cpp的时候要链接libfmt.a库文件。如果不知道库文件的名字,可以去lib文件夹下查看。

命令行好麻烦

你会觉得手动书写上述命令行好麻烦,对吧?如果你使用cmake或者xmake的话,只需要使用find_package(库)(cmake)或者add_requires("库")(xmake)就行了。它们会自动帮你处理上述的两个问题的。

  • 对cmake来说,库的名字应该填/share/cmake/Modules下的Find<库名>.cmake所对应的名字
  • 对xmake来说,上述cmake的包可以用add_requires("cmake::<库名>")来找到,也可以指定其他来源,或者直接从远程下载

5.3 杀毒软件

杀毒软件实时监测磁盘上的文件,会拖慢windows上的编译速度。特别是当项目较大,生成的文件比较多时,影响更为明显。此外,部分杀软还会将我们自己编写的程序识别为病毒。因此最好将常用的编写代码文件夹加入杀软的白名单/排除项。

但不管怎么样,windows上的编译速度一般还是比linux上慢不少

5.4 其他事项

5.4.1 Clang/LLVM工具链

这部分曾经想单独开一篇文章写,现在想想似乎也没有那么多内容,就在这里简要介绍一下吧。

  • clangd配合vscode上的同名插件,可以提供比vscode官方C++插件更好更快的语法高亮支持,不过需要注意生成compile_commands.json。(强烈推荐
  • lldb配合CodeLLDB插件提供更加强大的调试功能(可以调试Rust代码,可以嵌入python脚本来在调试时做内存可视化),不过如果不写rust的话与官方插件差别不大,可酌情安装
  • clang-format是现在通用的C/C++格式化工具,vscode的clangd插件和C++官方插件都支持它,不必额外安装插件
  • clang-tidy是一个基于AST的代码规范工具,可以自动检查出代码中性能不佳或者不合代码规范的问题,对于部分问题还可以提出修复方案。clangd插件对其有部分支持,完整支持需要独立插件,请酌情安装

安装则只需用pacman把UCRT环境的clang-tools-extra和lldb安装上就行了。如果启用clangd,但仍想使用官方插件的调试功能,可以在设置把官方插件的intellisense engine和autocomplete都给关掉以免冲突。

5.4.2 Windows Terminal

如果你在电脑上安装了很多环境,就会发现有一大堆各种不同的命令行入口,管理起来十分不便。使用windows terminal可以将各种命令行界面入口整合到一起,界面也更加美观,还能改善部分命令行界面的复制粘贴体验(点名批评MSYS2/git bash这一系列的shell)。

VSCode + MSYS2搭建C/C++开发环境 - 图14

使用windows terminal管理各种命令行入口

windows terminal可以直接在win10自带的微软商店里免费下载。而在win11则是默认的命令行程序(但是仍然推荐去商店更新一下,因为自带的版本比较古旧,甚至没有图形化的设置界面)。

5.4.3 WIN7/8

已经是2022年了,由于Cygwin即将移除win7/win8的支持,MSYS2也将紧随其后,在2022年底结束对win7/8的支持(但应该仍然支持win8.1)。

所以如果你还留在win7/win8,那么MSYS2对你来说可能不是个好选择。使用其他版本的发行版(比如winlibs),并且使用xmake/conan/vcpkg等工具完成包管理或许更好?

5.4.4 把%MSYS2%/usr/bin加入path变量?

这是个危险操作,不是很建议这么干,因为很可能遇到很多问题。如果你需要在cmd里面执行linux的命令,考虑利用wsl。如果你想在MSYS2的shell外面使用pacman,可以新建如下pacman.cmd文件放到path变量中的路径下。

@echo off %MSYS2%\usr\bin\pacman.exe %*

不过要注意在MSYS2外部安装/更新MSYS子环境的包会出问题,需要进入MSYS的shell重新安装一遍。

5.4.5 在pacman -Ss中屏蔽掉不想要的子环境

打开%MSYS2%/etc/pacman.conf,到最下面用#注释掉不想要的子环境源。

# 如果不想在pacman -Ss里看到mingw32环境的包 #[mingw32] #Include = /etc/pacman.d/mirrorlist.mingw

6. 推荐的参考书和工具网站

6.1 入门C/C++的用书推荐

  • C Primer Plus (C语言的内容)
  • C++ Primer Plus (C++11及以前的内容)
  • 高速上手现代C++ (现代C++(C++11/14/17/20)的新发展,建议配合上一本食用。本书仍在写作中,作者是国人大佬,目前开源在Github上

如果能魔法上网,那么也可以关注油管上Cpp Conference的频道,通过Cpp会议大牛的演讲来了解C++.

6.2 常用的工具网站

  • C/C的各种标准库函数怎么用可以查阅cppreference或者cppreference(中文)。这个网站的内容基于C和C最新的标准草案内容编写,关于标准库的内容最新,也最齐全。

VSCode + MSYS2搭建C/C++开发环境 - 图15

cppreference

  • 在线编译器网站:compiler explorer. 可以在线编译C/C++的函数,观察不同的编译器,不同的优化级别下生成的汇编代码。同时也支持rust,haskell等其他语言。

VSCode + MSYS2搭建C/C++开发环境 - 图16

compiler explorer

  • 在线对比两段代码的速度:Quick C++ Benchmark. 基于Google的benchmark框架,需要学习google benchmark的语法才能使用。

VSCode + MSYS2搭建C/C++开发环境 - 图17

Quick C++ Benchmark

结语

各种配置过程已经在虚拟机上测试过了,应当没有问题,也欢迎各位交流讨论。

最后感谢各位耐心阅读~

Change Logs

2022/06/28

  • 添加ChangeLog,替换了部分老旧链接
  • 修正一些错误,重写了#5
  • 考虑到win7/8即将结束支持,子环境选择上改为推荐UCRT64
  • 由于我已经迁移到win11,所以增加了一些win11相关内容

2021/11/19

  • 重组和精简部分内容
  • 更新MinGW/MSYS2历史相关
  • 添加命令行使用gcc相关