【VS Code】Windows10下VS Code配置C/C++语言环境

这篇文章属于本人参考诸多博客、教程、文档等资料,所撰写的「Windows10上配置VS Code」系列文章之一,内容随时可能发生更新变动,欢迎关注和收藏VS Code系列配置总目录一文以作备忘。

由于DevC++太过落后和老旧,而C/C++是本人最经常使用的语言,于是下定决心转向VS Code。现在有了VS Code编辑器,为了完成相关语言环境的配置,我们需要做只有下载编译套装、安装支持插件和书写配置文件三件事……听起来好多啊。


1. 下载安装MinGW-w64

共通的第一步已经完成,即获取编辑器。接下来要做的就是获取C/C++编译套装。常见的C/C++编译工具有GCC(GNU Compiler Collection ,即GNU编译器套件,GCC过去代表GNU C编译器,但是由于编译器支持除C之外的其他几种语言,它现在代表GNU编译器套件集合,GCC官网在此处)、Clang(C language family frontend for LLVM ,提供兼容GCC的编译器驱动程序 clang.exe 和兼容MSVC的编译器驱动程序 clang-cl.exeClang官网在此)、MSVC(Microsoft C++ 编译器工具集)三巨头,个人觉得Clang的架构更优雅、优化更惊艳,然而姜还是老的辣……在对C++ 20的语核支持“比赛”中,GCC首先接近了终点——虽然MSVC一个月前宣布自己冲过了终点。

MSVC compiler toolset is now C++20 feature-complete
– C++20 immediate functions & constinit support added in 16.10

此处要使用的GCC是MinGWMinimalist GNU for Windows),MinGW是一个Windows特定头文件和GNU工具集的集合,是为了那些不喜欢工作在Linux而留在Windows的人提供的一套符合标准的GNU工作环境。MinGW实际上就是将GCC移植到了Windows平台上,并且包含了WIN32 API,可以将源代码编译为能在Windows中运行的可执行程序,还可以使用一些Linux下的开发工具。

MinGW目前可以分为MinGW和MinGW-w64,前者只能够编译32位可执行程序,已经停止更新,后者可以编译32位或64位可执行程序,是MinGW的标准版本。最终要下载的是MinGW-w64下载地址点此处。找到下面这个并下载:

下载可能比较慢,耐心等待中……下载完成后还需要解压得到mingw64文件夹,将该文件夹拖到一个合适的、不包含中文地址的位置,如 C:\Program Files 。打开 C:\Program Files\mingw64\bin ,里面有许多可执行程序,gcc.exe 是C程序的编译器,g++.exe 是C++的编译器,gdb.exe 是调试程序的Debug工具:

为了让程序能够访问这些可执行程序,需要将目录 C:\Program Files\mingw64\bin 添加到环境变量中。这里可以看到,本人已经将这一目录添加到系统变量的Path中(用户变量只对当前用户有效,系统变量对所有用户有效):

现在进行验证,在CMD中输入 gcc --version ,可以看到如下版本信息,说明GCC已经安装成功:

现在电脑里面有了编辑器VS Code和编译套装GCC,它们下载自不同的网站,安装在不同的位置,彼此之间没有任何联系。而下面,我们将建立这一条道路,将两者关联起来。


2. 语言环境的文件结构

不过在此之前,一个题外但又很重要的事情是,我们需要辨析语言学习环境和实际项目开发环境这两者之间的区别。一个关键性的不同是二者的文件结构——或者说,组织和决定文件夹与文件之间的嵌套从属关系的方法。

在学习一门语言时,无论是C/C++/Haskell/Java/Python/Racket/Rust/Scala,我们多数情况下有的都是单个文件,了不起会有一些简单的小项目,涉及到几个简单头文件和源文件的组合。实际的项目开发就复杂多了,可能会有 build, lib, makefile, CMakeLists 等文件/文件夹,以及一系列的音频、视频和图片资源文件。由于此处介绍的是语言学习环境,我们的文件结构必须方便新建单个语言文件、编译调试、管理查看等,而不是学一点什么知识就要新建一个项目。

因为本人打算用VS Code统一组织和管理各个语言学习环境,所以新建了一个名为 C:\CodeWorld 的文件夹,将所有语言学习代码放在这里面。接着在里面新建了 Code_C, Code_Cpp, Code_Haskell, Code_Java, Code_Python, Code_Rust 等文件夹,在 Code_Cpp 中新建了 Cpp_Single, Cpp_Multiple 两个文件夹作为工作区文件夹。

其后开发实际项目时,也可以同样在 CodeWorld 文件夹下进行组织,比如从Github克隆项目时,建立一个 Github 文件夹;自己做项目时,建立一个 Projects 文件夹……

下面看一下语言学习环境下的工作区文件夹,以 C_Single 为例组织文件结构。首先要有一个 .vscode 文件夹,存储相应的配置文件。然后要有源文件,这些源文件可以分类进不同的文件夹,比如按照章节分或者按照类型分。我个人的分类比较细致,包括不同OJ的文件夹、不同技术书的文件夹等等,这里不一一列出。这些分类文件夹中都会有一系列的单个源文件,分别编译出的 .exe 文件一多,就容易杂乱,因此我们统一将这些可执行文件放到每个分类文件夹下的 bin 文件夹。一个示例如下:

C_Multiple 类似于此,也有 .vscode 文件夹,有分类文件夹,但是每个分类文件夹中都是一系列的小项目文件夹,小项目文件夹中包含一组源文件和编译出的 .exe 文件,不需要单独的 bin 文件夹。一个示例如下:

这就是一个合格的语言学习环境需要的文件结构,下面可以开始安装对应插件、书写相关配置文件。


3. 安装C/C++支持插件、书写配置文件

为什么要安装插件、配置文件呢?我们都知道,通过命令行使用 gcc 命令,能够编译生成可执行文件,但是每次都用命令行就太麻烦了。VS Code通过安装的插件和 .vscode 文件夹下的JSON配置文件(JSON文件的写法是VS Code官方规定的,可以看相关文档),帮我们实现了这些功能——一个是 tasks.json 文件,编译和执行就是我们想要VS Code执行的任务,因此 tasks.json 中要写两个 taskBuild, Run构建 Build 任务包括预编译、编译 compile 、链接等过程。除了构建执行外,还需要进行调试 Debug ,这就需要通过另一个 launch.json 文件与调试插件来实现。注意,tasks.json 中的任务 Build 应在 launch.json 中的 Debug 之前执行。此外还有一个 c_cpp_properties.json 文件,用于实现某些关于C/C++语言特性的功能。

听上去很麻烦是吧?不过这还没到时候呢,本部分内容只是入门引导,用于C/C++语言学习。真要实打实开发C/C++项目,还需要先学GCC、Makefile、CMake,学习如何链接静态/动态库,如何引入头文件、解决文件冲突等等。这些知识又是进阶学习必不可少的,不会系统构建就等于C/C++停留在入门水平,只能做些玩具项目

然而一个很现实的问题是,关于C/C++构建系统的资料太少了,C/C++书籍大多也不讲这些生态;Visual Studio那一套系统构建还和Unix/Linux环境不兼容……种种原因导致新手入门十分困难。可以预见的是,这些内容都学完、这些坑都踩完还要很久,不过这个时候回头再去用IDE,就会有一种了然于心的透彻感。

3.1 安装C/C++支持插件

官网Debugger extensions 一栏中已经说明,VS Code有对 Node.js 运行时的内建支持,因此可以调试JavaScript、TypeScript和其他能够转写到JavaScript的编程语言。对于其他语言,就需要安装 Debugger extensions 了。首先下载C/C++的支持插件(一个技巧是:在扩展搜索栏中输入 @category:"programming languages" @sort:installs ,就会列出所有语言相关的扩展):

可以看到,这一插件支持的编译套件和平台包括 Windows+MSVC/GCC and Mingw-w64, Windows Subsystem for Linux(WSL)+GCC, Linux+GCC, macOS+Clang 几种,它的功能包括,可以仔细看一下这些链接:

然后是 Native Debug 插件,方便调试:

3.2 书写C/C++单文件下配置文件,尝试构建、运行与调试

安装后重启VS Code,在文件->打开文件夹下,打开 C_Single 文件夹,此时VS Code中打开的根目录即是 C_Single(如果不额外设置JSON配置文件中的 optionsC_Single 作为工作区根目录,也是已执行程序的当前工作目录),由于是新建的文件夹,里面没有文件:

方法有很多种,这里我们新建一个名为 t.c 的文件,输入如下代码:

#include <stdio.h>
int main() {
    printf("Hello VS Code!");
    return 0;
}

然后点击运行,弹出的界面如下:

点击启动调试

需要选择 C++ (GDB/LLDB)Native Debug 插件支持):

  • 如果选择了默认配置,会生成 .vscode 文件夹和其中的 launch.json 文件用于调试,JSON文件内容如下,还需要自行修改:
    {
        // 使用 IntelliSense 了解相关属性。 
        // 悬停以查看现有属性的描述。
        // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
                "name": "(gdb) 启动",
                "type": "cppdbg",
                "request": "launch",
                "program": "输入程序名称,例如 ${workspaceFolder}/a.exe",
                "args": [],
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "miDebuggerPath": "/path/to/gdb",
                "setupCommands": [
                    {
                        "description": "为 gdb 启用整齐打印",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            }
        ]
    }
    
  • 如果选择了生成和调试活动文件,同样会生成 .vscode 文件夹和其中的tasks.json, launch.json 文件,JSON文件内容如下,此时不需要修改,可以直接进行构建、运行和调试(先打断点)
	//tasks.json
	{
	    "tasks": [
	        {
	            "type": "cppbuild",
	            "label": "C/C++: gcc.exe 生成活动文件",
	            "command": "C:\\Program Files\\mingw64\\bin\\gcc.exe",
	            "args": [
	                "-g",
	                "${file}",
	                "-o",
	                "${fileDirname}\\${fileBasenameNoExtension}.exe"
	            ],
	            "options": {
	                "cwd": "${fileDirname}"
	            },
	            "problemMatcher": [
	                "$gcc"
	            ],
	            "group": {
	                "kind": "build",
	                "isDefault": true
	            },
	            "detail": "调试器生成的任务。"
	        }
	    ],
	    "version": "2.0.0"
	}
	//launch.json
	{
	    // 使用 IntelliSense 了解相关属性。 
	    // 悬停以查看现有属性的描述。
	    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
	    "version": "0.2.0",
	    "configurations": [
	        {
	            "name": "gcc.exe - 生成和调试活动文件",
	            "type": "cppdbg",
	            "request": "launch",
	            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
	            "args": [],
	            "stopAtEntry": false,
	            "cwd": "${fileDirname}",
	            "environment": [],
	            "externalConsole": false,
	            "MIMode": "gdb",
	            "miDebuggerPath": "C:\\Program Files\\mingw64\\bin\\gdb.exe",
	            "setupCommands": [
	                {
	                    "description": "为 gdb 启用整齐打印",
	                    "text": "-enable-pretty-printing",
	                    "ignoreFailures": true
	                }
	            ],
	            "preLaunchTask": "C/C++: gcc.exe 生成活动文件"
	        }
	    ]
	}

或者点击以非调试模式运行

还是需要选择 C++ (GDB/LLDB)

  • 如果选择了默认配置,会生成 .vscode 文件夹和其中的 launch.json 文件用于调试,JSON文件内容同上面的默认配置,还需要自行修改。
  • 如果选择了生成和调试活动文件,同样会生成 .vscode 文件夹和其中的 tasks.json, launch.json 文件,JSON文件内容同上,此时不需要修改,可以直接进行构建、运行和调试(先打断点)

总的来说,以非调试模式运行感觉和启动调试没有什么区别,在存在程序源文件时添加配置也是一样的(打开文件夹但是不存在源文件时只会创建 lauch.json 文件;如果没有打开文件夹,添加配置会打开全局配置 settings.json 文件)。不过这三者都不太符合我们的预期文件结构。

我们可以自行在 C_Single 下创建 .vscode 文件夹以及其中的 tasks.json, launch.json 文件,文件具体内容如下,注释比较详细,一些路径可能需要修改,以符合上一节中提到的工作区文件结构:

//tasks.json
{   
    //欲了解更多信息,请访问:
    //https://code.visualstudio.com/docs/editor/tasks#vscode
    "tasks": [
        { //这个大括号里是构建Build任务
            //label是任务的用户界面标签,可以更改
            "label": "build", 
            //type定义任务是被作为进程process运行(VS Code会把预定义变量和转义解析后全部传给command) 
            //还是在shell中作为命令运行(相当于先打开shell再输入命令,args会经过shell再解析一遍) 
            "type": "shell", //cppbuild 
            //command是要执行的(编译)命令,可以是外部程序或者shell命令
            //没有添加环境变量时,类似于在命令行执行"C:\\Program Files\\mingw64\\bin\\gcc.exe" 其他参数
            //添加了环境变量后,可以只写"gcc"
            "command": "gcc", //编译C++需要换成g++
            //args是调用此任务(即label所标明的任务)时需要传递给命令(即command指定的命令)的系列参数,以实现功能
            "args": [
                "-g",       //生成和调试相关的信息
                "${file}",  //承接上一步的-g,指定要编译的是当前正在编辑的文件,${file}包括绝对路径/文件名.文件后缀名
                "-o",       //指定输出文件的路径和名称
                "${fileDirname}\\bin\\${fileBasenameNoExtension}.exe", //承接上一步的-o,
                //让可执行文件输出到源码文件所在的文件夹下的bin文件夹内,并且让它的名字和源码文件相同
                //${fileDirname}是当前打开文件所在的文件夹绝对路径,不包括文件名
                //${fileBasename}是当前打开的文件名.后缀名,不包括路径
                //${fileBasenameNoExtension}是当前打开文件的文件名,不包括路径和后缀名
                //${fileExtname}是当前打开文件的后缀名
                //即 ${fileDirname}/${fileBasename}
                //                  |{fileBasenameNoExtension}.${fileExtname}|
                //   |--------${file}-------------|
                "-Wall",                //开启额外警告
                "-static-libgcc",       //静态链接libgcc
                //"-fexec-charset=GBK", //生成的程序使用GBK编码,不加此条可能导致Win下输出中文乱码
                "-std=c11",             //语言标准,根据需要进行修改,写C++时可以换成C++的语言标准,比如C++17
            ],  
            //group表示组,我们可以有很多的task,然后把它们放到一个组里面
            //此处定义此任务属于执行组,它支持"build"以将其添加到生成组,也支持"test"以将其添加到测试组
            "group": { 
                "kind": "build",  //表示这一组的任务属于执行组
                "isDefault": true //表示此任务是当前这组任务中的默认任务
            },
            //problemMatcher是要使用的问题匹配程序,
            //可以是一个字符串或一个问题匹配程序定义,也可以是一个字符串数组和多个问题匹配程序
            //捕捉编译时编译器在终端里显示的报错信息,将其显示在vscode的'问题'面板里
            "problemMatcher": [ 
                "$gcc"
            ], 
            //presentation配置用于显示任务输出并读取其输入的面板
            "presentation": {
                "echo": true,       //控制是否将执行的命令显示到终端面板中,默认值为true
                "reveal": "always", //控制运行任务的终端是否显示,默认设置为always,总是在此任务执行时显示终端;或者为silent/never
                "focus": false,     //控制终端面板是否获取焦点,默认值为false;如果设置为true,面板也会显示,但对编译来说设为true没有意义,因为运行时才涉及到输入
                "panel": "new"      //控制是否在任务间共享终端面板,同一个任务使用相同面板shared(会出现"任务被终端重用"),还是每次运行时新创建一个面板new
            },
            "detail": "调试器生成的任务。"
        },
        { //这个大括号里面是运行Run任务,一些设置与上面的构建任务性质相同
            "label": "run",
            "type": "shell",
            "dependsOn": "build", //此任务依赖的另一任务,因为必须先构建然后运行,所以执行此任务前必须先执行build任务
            "command": "${fileDirname}\\bin\\${fileBasenameNoExtension}.exe", //执行exe文件,只需要指定这个exe文件在哪里
            "group": {
                "kind": "test", //表示这一组是测试组,将run任务放在test组里方便我们用快捷键执行
                "isDefault": true //表示此任务是当前这组任务中的默认任务
            },
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": true, //运行run任务后将焦点聚集到终端,方便进行输入
                "panel": "new"
            }
        }
    ],
    "version": "2.0.0"
}
//launch.json
{
    //使用 IntelliSense 了解相关属性。 
    //悬停以查看现有属性的描述。
    //欲了解更多信息,请访问:
    //https://code.visualstudio.com/docs/editor/debugging#_launch-configurations
    "version": "0.2.0",
    "configurations": [ 
        { //这个大括号里是我们的调试Debug配置
            "name": "Debug",        //配置名称
            "type": "cppdbg",       //配置类型,cppdbg对应cpptools提供的调试功能,可以认为此处只能是cppdbg
            "request": "launch",    //请求配置类型,可以是启动launch或附加attach
            "program": "${fileDirname}\\bin\\${fileBasenameNoExtension}.exe", //将要进行调试的程序可执行文件的完整路径
            "args": [],             //程序调试时传递给程序的命令行参数,这里设为空即可
            "stopAtEntry": false,   //设为true时调试程序将暂停在程序入口处,相当于在main上打断点;如果传递了processId则不起任何作用
            "cwd": "${fileDirname}",//调试程序时的工作目录,此处为源码文件所在目录
            "environment": [],      //要添加到程序环境的环境变量,这里设为空即可
            "externalConsole": false, //为true时使用单独CMD窗口,跳出小黑框;设为false则用VS Code的内置终端,建议用内置终端
            "internalConsoleOptions": "neverOpen", //如果不设为neverOpen,调试时会跳到“调试控制台”选项卡,新手调试用不到
            "MIMode": "gdb",        //指定MIDebugEngine连接的控制台调试程序,gdb是minGW中的调试程序
            "miDebuggerPath": "C:\\Program Files\\mingw64\\bin\\gdb.exe", //MI调试程序(如gdb)的路径;如果未指定,将首先在路径中搜索调试程序
            "setupCommands": [ //为了安装基础调试程序而执行的一个或多个GDB/LLDB命令
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build" //调试开始前执行的任务,我们在调试前要编译构建,与tasks.json的label相对应,名字要一样
        }
    ]
}

到目前为止,差不多完成了 C_Single 下语言学习环境的配置。先来一个简单的Hello程序,尝试一下编译、运行、调试。首先要在 C_Single 中新建一个分类文件夹,假设为 temp ,再在 temp 文件夹下建立 bin 文件夹,然后在 temp 下新建 hello.c 文件,hello.c 中输入代码如下:

现在可以通过 终端-运行生成任务… 或者 Ctrl+Shift+B ,来仅编译构建 Build 。此时终端面板打开并显示如下,没有报错,而且在 C_Single/temp/bin 下多了 hello.exe ,构建成功:

再尝试一下编译构建+运行,使用 Ctrl+K Ctrl+S 打开键盘快捷方式,搜索任务两个字,找到运行测试任务(默认没有快捷键,先前我们在 tasks.json 中将 run 任务设为测试组,正是为了此处),点击左侧的加号添加快捷键绑定。由于启动调试设为 F5 ,这里将运行测试任务设置为 F4

然后回到 hello.c 界面,按下F4,结果如下,输入名字并按下回车,运行成功:

最后是调试,我们在第一个 printf 前打上断点,然后要么使用调试快捷键 F5 ,要么通过运行-启动调试

点击单步调试按钮,或者使用快捷键 F11 ,向下执行程序,黄色箭头的那一行是现在未执行、下一步将要执行的语句,执行到输入语句时黄色箭头消失,需要在终端面板中输入+回车,接着黄色箭头出现,可以继续向下执行,直到调试成功。

现在我们已经可以新建C源文件写程序,F4 一键编译构建+运行,F5 一键开始调试——和别的IDE的体验是不是差不多了?!类似的,我们在 Code_Cpp/Cpp_Single 中添加 .vscode 文件夹和 tasks.json, launch.json 文件(只需要修改前面给出的相关JSON代码,命令中 gcc 改为 g++ ,添加一个静态链接到 libstdc++ ,标准改为 -std=c++17 ,注意 "problemMatcher" 仍为 ["$gcc"] ),也尝试一下构建、运行和调试。

3.3 书写C/C++多文件下配置文件,尝试编译、运行和调试

搞定了 C_Single ,简单多文件的 C_Multiple 也就类似了。只是需要修改一下两个JSON文件中涉及到路径的部分。新文件如下:

//tasks.json
{
   "version": "2.0.0",
   "tasks": [
       {
           "label": "build",
           "type": "shell",
           "command": "gcc",  
           "args": [
               "${fileDirname}\\*.c", //***
               "-o",
               "${fileDirname}\\${fileBasenameNoExtension}.exe", //***
               "-g",
               "-Wall", 
               "-static-libgcc",   
               "-fexec-charset=GBK",
               "-std=c11",   
           ],
           "group": {
               "kind": "build",
               "isDefault": true
           },
           "presentation": {
               "echo": true,
               "reveal": "always",
               "focus": false,
               "panel": "new"
           },
           "problemMatcher": "$gcc"
       },
       {
           "label": "run",
           "type": "shell",
           "dependsOn": "build",
           "command": "${fileDirname}\\${fileBasenameNoExtension}.exe", //***
           "group": {
               "kind": "test",
               "isDefault": true
           },
           "presentation": {
               "echo": true,
               "reveal": "always",
               "focus": true,
               "panel": "new"
           }
       }

   ]
}
//launch.json
{
    "version": "0.2.0",
    "configurations": [{
        "name": "Debug", 
        "type": "cppdbg", 
        "request": "launch",
        "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", //***
        "args": [],
        "stopAtEntry": false, 
        "cwd": "${fileDirname}", 
        "environment": [], 
        "externalConsole": false,
        "internalConsoleOptions": "neverOpen",
        "MIMode": "gdb", 
        "miDebuggerPath": "C:\\Program Files\\mingw64\\bin\\gdb.exe", 
        "preLaunchTask": "build" 
    }]
}

注意,C_SingleC_Multiple 文件夹的文件结构是不同的,写单文件时用前者(要建立一个 bin 文件夹),写多文件时用后者。

类似的,我们在 Code_Cpp/Cpp_Multiple 中添加 .vscode 文件夹和 tasks.json, launch.json 文件(只需要修改前面给出的相关JSON代码,命令中 gcc 改为 g++ ,添加一个静态链接到 libstdc++ ,标准改为 -std=c++17 ,注意 "problemMatcher" 仍为 ["$gcc"] ),然后写一个简单的多文件C++项目,尝试一下构建、运行和调试。

值得一提的是,VS Code在针对C++多文件编译时,可能不是那么友好,需要再搭配上CMake来使用,以后会介绍这方面的知识。

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

memcpy0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值