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输入cmd
或powershell
来启动它们。启动后会有一串字符提示你现在在哪个路径下,我们可以通过cd
命令来切换当前所在的路径。
小技巧:在文件管理器按F4会跳到路径栏,输入cmd并回车即可在此文件夹打开cmd(不用再
cd
了)。
- 不知为何windows自带的powershell不能这么打开
- win11的用户可以直接右键在当前路径打开Windows Terminal
1.2.1 在命令行界面运行程序
只要输入一个程序的相对路径或者绝对路径,就能够运行那个程序(可以不用写.exe
)
以powershell启动steam为例:
# powershell启动steam
cd E:\steam_main # 首先cd到steam.exe所在的文件夹
.\steam
# 或者直接使用绝对路径
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
,可以直接在命令行查找、安装和卸载各种第三方库和开发工具。
# 比如你想要安装opencv库
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官网下载安装程序即可。安装过程就是选安装位置,然后一直点下一步,没有什么需要特别注意的地方。
点击图中所示位置下载MSYS2
2.3.2 MSYS2的子环境(选读)
MSYS2实际上是由6个独立的子环境组成的。每个子环境会有一个单独的文件夹,和一个专门的命令行界面入口,具体区别见下图。一般来说,直接使用UCRT64就行。
MSYS2包含的几个子环境
打开MSYS2的安装目录,可以看到这些子环境的位置。刚安装好MSYS2的话,除了usr文件夹以外,其它的子环境文件夹里应该还都是空的。
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工具链。中间出现询问之类的一路回车就好,等待一段时间后应该就安装完毕了。
安装mingw工具链
安装完成后ucrt64/bin文件夹下应该能找到gcc.exe
,然后将此路径加入环境变量。
如果一切正常,那么打开命令行,输入gcc --version
应当能显示gcc
的版本,MSYS2目前的gcc版本是12.1.0 Rev2
。
如果提示找不到gcc或者gcc不是批处理等错误,可以尝试关闭重开powershell/cmd再次尝试,如果仍然失败,那么应当是环境变量没有设置对。
检查gcc版本
如果没有问题,那么我们的编译器就安装成功啦。
2.4 在命令行使用gcc(选读)
事实上,我们现在已经可以写C/C++代码并运行了。例如,新建一个文本文件hello.c
,内容如下
#include <stdio.h>
int main(void) {
puts("Hello, world!");
return 0;
}
然后在这个路径下命令行输入gcc hello.c -o hello
,就能生成一个hello.exe
文件,在命令行运行它就能看到输出。(不要双击运行它,因为运行结束后默认会退出命令行界面,你就看不到输出了!)
命令行编译运行
简单来说,输入gcc <源代码文件> -o <输出程序名字>
就可以将C代码文件编译成指定名字的可执行文件。而对于C代码,将gcc换成g就行。
如果你能接受使用Notepad2之类的轻量化编辑器加上手打命令行编译运行的话,也够应付刚入门时的各种单文件小程序了(不过缺点是不能调试)。
而在VSCode(和各种IDE)中,本质上就是将这里这个手动输入命令行的过程自动化了。
3. 安装并配置VSCode
3.1 下载安装VSCode
去VSCode官网下载安装包,按照提示安装就行。
建议勾选在右键菜单中添加“通过code打开”,方便我们在指定位置打开vscode。
勾选“通过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++代码。
安装插件
打开设置,勾选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的原理就是自动在命令行输入编译和运行的命令,和我们自己手动输入命令没有区别。
输入的命令也可以在相应的插件设置中进行修改。
使用code runner运行C代码
4.2 单文件的调试
按下F5,依次选择C++(GDB/LLDB)和我们MSYS2环境中的gcc.exe,VSCode会自动生成配置文件,并生成调试。
可以在行号的左边单击来设置断点,程序运行到断点前会自行中断。左侧可以看到此时各个变量的值,监视栏中可以输入表达式观察。
VSCode调试界面
另外,目前VSCode支持了条件断点,只要右键断点,选择编辑断点即可设置中断条件,具体使用方法可以参考VSCode文档。
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.json
和task.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)。
使用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最新的标准草案内容编写,关于标准库的内容最新,也最齐全。
cppreference
- 在线编译器网站:compiler explorer. 可以在线编译C/C++的函数,观察不同的编译器,不同的优化级别下生成的汇编代码。同时也支持rust,haskell等其他语言。
compiler explorer
- 在线对比两段代码的速度:Quick C++ Benchmark. 基于Google的benchmark框架,需要学习google benchmark的语法才能使用。
Quick C++ Benchmark
结语
各种配置过程已经在虚拟机上测试过了,应当没有问题,也欢迎各位交流讨论。
最后感谢各位耐心阅读~
Change Logs
2022/06/28
- 添加ChangeLog,替换了部分老旧链接
- 修正一些错误,重写了#5
- 考虑到win7/8即将结束支持,子环境选择上改为推荐UCRT64
- 由于我已经迁移到win11,所以增加了一些win11相关内容
2021/11/19
- 重组和精简部分内容
- 更新MinGW/MSYS2历史相关
- 添加命令行使用gcc相关