VS Code 调试 C 程序配置

37 阅读5分钟

最近需要用 VS Code 编写和调试 C语言程序,折腾了下 VS Code 调试相关配置,顺带记录一下。

VS Code 调试基础

VS Code 其实是个文本编辑器,类似 notepad,只是现在我们需要它像 IDE 一样调试简单的程序,而它也希望我们这么做。

之前我们用的 IDE 大多为单一语言配置,功能强大,但也臃肿,所以在一些情况下,我们需要一个启动速度快,轻量的工具来编辑代码和简单调试。VS Code 大概做了这么一件事:以文本编辑为基础,提供一些基本框架,我们可以在此基础上,安装对应的扩展插件,自己攒出一个简单的 IDE,像组装电脑一样。

所以,这里引出一个问题,在我们按F5或点击界面上的调试运行按钮时,VS code不知道我们要如何调试程序,例如我最常见的需求:

  • 指定程序入口和传入参数
  • 配置用于相对路径启动目录,就是pwd
  • 调试之前如何构建,例如gcc编译器编译c语言程序想debug的话,需要在编译时传入额外的命令 -g调试符号(debug symbols) 嵌入到生成的可执行文件中

所以,我们需要进行一些配置,告诉 VS Code 这些信息。而 VS code 给出的方案是launch.json文件。

创建 launch.json

VS Code 将默认调试配置文件存储在当前工作区(即项目文件夹)下的 .vscode 文件夹中。名为 launch.json 的文件。 但这个文件不是一开始就存在的,需要我们主动创建。主要有两种创建方式:

  1. 纯手动直接新建这个文件并编辑其内容。
  2. 通过GUI界面和内置或插件提供的预制配置半自动创建。

这两种方式是只要文件内容一样,结果就是一样的。这里简单记录下半自动创建的过程:

  1. 打开一个工作区(文件夹)后,点击 GUI 界面的 debug 按钮,可以看到如图界面,点击创建一个 'launch.json' 文件。

image.png

  1. 这时 VS Code 会猜测你要调试的程序类型,弹出一些选项。主要根据你安装的插件,所选的文件类型等。例如我当前工作目录为空,他会根据我的插件猜测CMake或Python或内置的Node.js

image.png

  1. 但当我新建并选中了一个main.c的空文件后,它就会猜到并提示C/C++程序,这里因为主要目的是 Debug,所以就选 GDB/LLDB 。他们来自官方的 C/C++ 插件。然后会自动创建.vscode文件夹和其中的launch.json文件。

image.png

  1. 创建文件后,会自动进到 launch.json 文件,并定位到 configurations 属性配置位置。并弹出一些可选的预制配置选项。如果没出现预制选项,可以点击右下角的添加配置按钮。 这里因为我希望用 gdb 调试 c程序,所以选择来自 C/C++ 插件的 (gdb) 启动

image.png

  1. 于是预先配置的 gdb 调试 C 程序 的模板就被添加到了 launch.json 文件。

image.png

这里可以创建多个自己的常用配置,后续可以简单切换。

接下来就是配置具体的每个选项,毕竟预制模板只是模板,还需要手动改为自己的需要。

配置 launch.json 选项

"configurations" 列表里,每个花括号内为一组配置。 这里简单记录下每组配置里,一些常用的选项

  • name - 必填,就是这组配置的名称,主要用于在GUI里选择和切换时区别

  • type - 必填,调试器的类型,和插件相关,C/C++ 插件提供的就是 cppdbg

  • request - 必填,调试的类型,c 程序常用 launch,就是从头开始。attach则用于程序已经运行,后补附加调试器的场景

  • program - 必填,表示启动的是哪个文件

这里 ${workspaceFolder} 为变量,就是当前工作目录,用变量指代文件名 常见的,在运行和调试单个文件时,常用变量指代所选.c生成的同名exe;调试多个文件生成的代码时,需要主动指定最终的执行文件入口:

  //调试单个文件
  "program": "${fileDirname}/${fileBasenameNoExtension}.exe",
  //多个文件生成一个exe,在固定位置
  "program": "${workspaceFolder}/build/main.exe",
  • args - 常用,用一个列表指定传入给程序的各个参数
    "args": ["123","abc","-d","-f", "xxxx"],
  • cwd - 常用,指定工作目录,就是从哪个位置开始,以相对路径查找依赖文件和其他文件
  • preLaunchTask - 关键, 在调试之前需要的前置动作,对于C程序来说,很关键

对于 C 程序,在调试前需要编译,也就是 编译->调试。所以,在调试前,需要执行一个编译动作。 我们可以在外面单独构建,然后执行调试。而VS Code 提供了一个更便捷的自动话方式,Task,(不展开讲了)。

简单来说,我们创建了一个自动化的任务,用于构建程序,然后把这个自动化任务的名称赋给 preLaunchTask属性,则在每次执行调试前,会自动先执行一遍构建动作。例如:

    "preLaunchTask": "debug build"

构建Task

构建任务这里不过多展开,大体就是在 .vscode 目录下创建一个 task.json 来定义一些任务。例如单个文件可以用如下简单配置,即根据所选文件名,通过 gcc 自动以debug模式命名构建一个.exe扩展名的同名文件。多个文件可以用 makecmake 命令。

{
    "version": "2.0.0",
    "tasks": [
      {
        "label": "Build Current File (with debug)",
        "type": "shell",
        "command": "gcc",
        "args": [
          "-g",
           "${file}",
           "-o",
           "${fileDirname}/${fileBasenameNoExtension}.exe"
         ],
         "group": "build",
         "presentation": {
           "echo": true,
           "reveal": "always",
           "focus": false,
           "panel": "shared"
         },
         "problemMatcher": "$gcc"
       }
     ]
}

执行调试

都配置完毕后,最后就是执行调试了。

一种是通过 GUI 界面的调试按钮,点击小绿三角,运行所选的调试配置开始执行。后面的名称就是之前在 launch.jsonconfiguration 内某组配置的 name 属性所指定的名称。 如果之前配置了多个不同的配置,可以通过下拉箭头快速切换。

image.png

或者通过快捷键 F5 来运行,等同于命令 > Debug: Start Debugging

注意: 但值得注意的一点是, Ctrl+F5 即 '以非调试模式运行', 并不是真的绕过 launch 配置,和直接编译执行不一样。 它还是通过 launch 配置进行构建和进入程序, 只是跳过了所有断点, 相当于一种特殊状态的 debug, 而不是我们理解的 release and run。