VScode中debug运行逻辑概述

工作区

VScode由两种运行模式:单文件打开模式和文件夹打开模式。界面上最明显的区分是VScode底部的颜色条如果是紫色的,说明在单文件打开模式,如果为天蓝色,即处于文件夹打开模式。

在文件夹打开模式下,左侧文件浏览器界面可以看到当前文件夹路径下的所有文件以及文件夹。这个所谓的“当前文件夹路径”在VScode中被称为“工作区路径”。如果不清楚当前的工作区路径,在VScode新建——注意不是显示之前隐藏的终端——一个终端后所处在的路径就是当前的工作区路径,由VScode自动帮你切换好了。可以在打开后不更改路径的情况下使用pwd命令打印当前的绝对路径。 打开新的终端并查看当前绝对路径

Debug相关配置文件

${workspaceFolder}表示当前工作区文件夹,则与这个工作区相关的所有VScode的配置文件都放在${workspaceFolder}/.vscode文件夹下,若要进行c语言程序的debug,需要用到两个文件:

launch.json

这个文件里面记录的是与debug直接相关的配置,包括debug任务名称、debug程序(c语言对应gdb)、相关参数等等。对于python这种不需要编译的解释性语言,仅用这个文件就够了。但是c语言是编译型语言,在调用gdbdebug之前还需要调用gcc进行编译,对应到launch.json里面就要配置一个参数"preLaunchTask",里面调用接下来要说的tasks.json文件里的配置进行编译。

tasks.json

这个文件就是一些常用任务的配置,写成配置文件后就可以一键运行,而不用每次都敲繁琐的命令行了。在debug的相关配置中常用来填写编译(build)任务的相关配置,里面可以指定使用的编译器、使用的语言版本、编译参数等等。

debug相关设置以及快捷键

  • F5在debug启动前为“启动debug”命令,在debug启动后为“继续”命令(继续运行直到遇到下一个断点暂停)
  • F9在光标所在的行设置断点
  • F10下一步,遇到函数不会进入
  • F11下一个语句,遇到函数会进入函数
  • shift + F11单步跳出,即执行完当前函数并返回后暂停程序
  • shift + F5停止debug

或者在遇到断点后点击debug工具栏里的按钮也可以 debug遇到断点后的界面

有可能启动debug之后弹出的终端界面在debug console中,而非terminal中,此时进行的输入不会被引导到stdin中,而是会交给调试器。点击下图中红框圈起来的terminal(中文翻译应该是“终端”)即可回到正常的终端,此时进行的输入将直接进入stdin交给程序。 debug console界面

更多进阶玩法参见微软官方文档

一次C语言Debug的流程(配合下文给出的配置)

  1. 在左侧的debug面板中选择debug任务名称(由于下文给出的配置中实际上只含有1个配置,会被默认选中,这步可以被跳过。但是如果有多个debug配置则需要先选中一个。)
  2. 打开含有main函数的c语言源文件,待会编译的时候默认当前打开的文件中含有main函数
  3. 摁下F5键,启动一个debug流程
  4. vscode按照选择的任务名称读取${workspaceFolder}/.vscode/launch.json文件,发现里面有参数"preLaunchTask"
  5. 于是vscode调用${workspaceFolder}/.vscode/tasks.json文件中指定的编译任务,调用gcc完成c程序的编译
  6. 完成编译后,vscode继续按照${workspaceFolder}/.vscode/launch.json文件中定义的debug配置调用gdb启动debug过程
  7. 程序遇到断点后暂停,此时可以在左侧debug面板中查看变量、调用栈等等信息
  8. 按下弹出的debug工具栏最右侧的红色方块停止debug

配置文件

windows和linux下的配置文件有所不同,请根据运行环境选择。在写入配置文件前请确认在终端中可以正常使用gccgdb命令。

Linux

tasks.json

{
  "tasks": [
    {
      "type": "cppbuild",
      "label": "C/C++: gcc build active file",
      "command": "/usr/bin/gcc",
      "args": [
        "-fdiagnostics-color=always",
        "-g",
        "${file}",
        "-o",
        "${fileDirname}/${fileBasenameNoExtension}",
        "-lpthread"
      ],
      "options": {
        "cwd": "${fileDirname}"
      },
      "problemMatcher": ["$gcc"],
      "group": "build",
      "detail": "compiler: /usr/bin/gcc"
    }
  ],
  "version": "2.0.0"
}

以上代码复制到${workspaceFolder}/.vscode/tasks.json中。

launch.json

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb) Launch",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}/${fileBasenameNoExtension}",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${fileDirname}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "Set Disassembly Flavor to Intel",
          "text": "-gdb-set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "C/C++: gcc build active file"
    }
  ]
}

以上代码复制到${workspaceFolder}/.vscode/launch.json中。

Windows

tasks.json

{
    "version": "2.0.0",
    "tasks": [
        { //这个大括号里是‘编译(build)’任务
            "label": "build", //任务名称,可以更改,不过不建议改
            "type": "shell", //任务类型,process是vsc把预定义变量和转义解析后直接全部传给command;shell相当于先打开shell再输入命令,所以args还会经过shell再解析一遍
            "command": "gcc", //编译命令,这里是gcc,编译c++的话换成g++
            "args": [ //方括号里是传给gcc命令的一系列参数,用于实现一些功能
                "${file}", //指定要编译的是当前文件
                "-o", //指定输出文件的路径和名称
                "${fileDirname}\\${fileBasenameNoExtension}.exe", //承接上一步的-o,让可执行文件输出到源码文件所在的文件夹内,并且让它的名字和源码文件相同
                "-g", //生成和调试有关的信息
                //"-Wall", // 开启额外警告
                //"-static-libgcc",  // 静态链接libgcc
                "-fexec-charset=GBK", // 生成的程序使用GBK编码,不加这一条会导致Win下输出中文乱码
                "-std=c99", // 语言标准,可根据自己的需要进行修改,写c++要换成c++的语言标准,比如c++11
                "-lpthread", //多线程程序需要使用
            ],
            "group": { //group表示‘组’,我们可以有很多的task,然后把他们放在一个‘组’里
                "kind": "build", //表示这一组任务类型是构建
                "isDefault": true //表示这个任务是当前这组任务中的默认任务
            },
            "presentation": { //执行这个任务时的一些其他设定
                "echo": true, //表示在执行任务时在终端要有输出
                "reveal": "always", //执行任务时是否跳转到终端面板,可以为always,silent,never
                "focus": false, //设为true后可以使执行task时焦点聚集在终端,但对编译来说,设为true没有意义,因为运行的时候才涉及到输入
                "panel": "new" //每次执行这个task时都新建一个终端面板,也可以设置为shared,共用一个面板,不过那样会出现‘任务将被终端重用’的提示,比较烦人
            },
            "problemMatcher": "$gcc" //捕捉编译时编译器在终端里显示的报错信息,将其显示在vscode的‘问题’面板里
        },
    ]
}

以上代码复制到${workspaceFolder}/.vscode/tasks.json中。可能有一些配置需要更改,阅读注释即可。

launch.json

{
    "version": "0.2.0",
    "configurations": [
        { //这个大括号里是我们的‘调试(Debug)’配置
            "name": "C Debug", // 配置名称
            "type": "cppdbg", // 配置类型,cppdbg对应cpptools提供的调试功能;可以认为此处只能是cppdbg
            "request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加)
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", // 将要进行调试的程序的路径
            "args": [], // 程序调试时传递给程序的命令行参数,这里设为空即可
            "stopAtEntry": false, // 设为true时程序将暂停在程序入口处,相当于在main上打断点
            "cwd": "${fileDirname}", // 调试程序时的工作目录,此处为源码文件所在目录
            "environment": [], // 环境变量,这里设为空即可
            "externalConsole": false, // 为true时使用单独的cmd窗口,跳出小黑框;设为false则是用vscode的内置终端,建议用内置终端
            "internalConsoleOptions": "neverOpen", // 如果不设为neverOpen,调试时会跳到“调试控制台”选项卡,新手调试用不到
            "MIMode": "gdb", // 指定连接的调试器,gdb是minGW中的调试程序
            "miDebuggerPath": "C:\\programming\\MinGW_w64\\mingw64\\bin\\gdb.exe", // 指定调试器所在路径,如果你的minGW装在别的地方,则要改成你自己的路径,注意间隔是\\
            "preLaunchTask": "build" // 调试开始前执行的任务,我们在调试前要编译构建。与tasks.json的label相对应,名字要一样
        },
    ]
}

以上代码复制到${workspaceFolder}/.vscode/launch.json中。"miDebuggerPath"中指定的gdb路径需要按照本地配置进行更改。

补充

首先,建议在vscode的插件界面中搜索并安装C/C++ Extension Pack

其次,存在更高阶也更简洁的debug配置——cmake,有兴趣可以搜索查看。