1. 前言:为什么要折腾 WSL?

临近期末,复习C语言时实在是受不了Visual Studio复杂的操作(还没法直接写C),但是用VScode又被Windows的终端编码(GBK)搞的痛不欲生

听说Linux编程配环境很容易,但是又不想放弃Windows的娱乐优势,所以学习了WSL来平衡二者。

这篇文章记录了从简单的命令行到GDB调试的全过程,用于备忘。

2. 环境准备与基础命令

2.1 环境架构

  • 系统: Windows 11 25H2 + WSL2 (我用的是 Ubuntu)
  • 编译器: GCC
  • 调试器: GDB
  • 编辑器: VS Code

2.2 WSL 基础命令

在 PowerShell 中,可以用几个简单命令管理 WSL:

# 启动并进入默认的 Linux 发行版
wsl

# 查看已安装的发行版及其版本(最好用WSL2)
wsl -l -v

注意:从隔离的角度考虑,最好在在 Linux 的 /home/用户名 目录下进行代码开发**,不要跨盘操作(如 /mnt/c)。

几个高频使用的终端命令:

pwd          # 确认当前路径
ls -l        # 列出文件详细信息
cd ~         # 快速回到 /home 目录,这里~=/home/用户名
mkdir code   # 创建项目文件夹,使用-p参数来递归创建文件夹

2.3 安装核心开发工具

刚装好的 Ubuntu 可能不带开发工具,需要手动安装 build-essential 包,它包含了 gcc, g++, make 等一系列开发必备工具。

sudo apt update
sudo apt install build-essential

3. GCC 和 GDB 常见命令与内部逻辑

在配置 IDE 之前,必须先熟练掌握底层的命令行逻辑。为了演示 GDB 的强大,我们先来写一段看似没问题但结果错误的代码。

3.1 这是一个有BUG的程序

创建一个名为 test.c 的文件,目的是计算 1 到 n 的和:

#include <stdio.h>

int main(){
    int n;
    int sum;
    scanf("%d", &n);

    for (int i = 1; i <= n; i++){
        sum += i;   
    }
    printf("%d\n", sum);
    return 0;
}

3.2 编译器 (GCC) 的标准命令

不要只会用 gcc test.c,养成添加标准参数的习惯,这能帮你发现无数潜在的 Bug。

# 推荐的编译指令,参数详解:
# -g       : 生成调试信息(GDB 调试必须加,否则看不到源码和变量名)
# -Wall    : 开启所有警告(这对排查隐患至关重要)
# -std=c11 : 指定 C11 标准,可以更换
# -o demo  : 指定输出的可执行文件名为 demo

gcc test.c -g -Wall -std=c11 -o demo 

3.3 一个用GDB排除BUG的案例

以下,我将会模拟一场真实的BUG排查。

第一步:编译并启动调试

gcc test.c -g -o demo 
gdb ./demo

第二步:打断点 我们希望程序停在 main 函数刚开始的地方,好让我们一步步观察。

(gdb) b main # b命令,打断点,支持按行数打断点
Breakpoint 1 at 0x1195: file test.c, line 3.

第三步:运行程序

(gdb) r # r命令,运行程序
Starting program: /home/yourname/code/demo 
Breakpoint 1, main () at test.c:3
3       int main(){

此时,程序停在了第 3 行,还没执行。

第四步:单步执行与查看变量 这是最关键的一步。我们往下走几步,看看 sum 的值。

注意,GDB只会检查执行语句,变量声明会直接跳过(除非变量在声明时就进行了赋值操作,如 int n = 0;),所以就从第3行跳到了第6行。

(gdb) n
6           scanf("%d", &n);
(gdb) n
5           #输入n的值
8           for (int i = 1; i <= n; i++){

此时,sum 已经被声明,但还没进入循环。让我们看看现在 sum 里面是什么:

(gdb) p sum # p命令,打印变量值
$1 = -8944 # 发现是一个奇怪的值,说明是内存中的垃圾值

得出结论:因为没有初始化 sum = 0,它直接拿内存里的垃圾值去累加了,所以结果会不对。

第五步:退出 (Quit) 找到问题后,退出 GDB 去修改代码。

(gdb) q # q命令,退出调试

4.配置 VS Code 实现一键图形化调试

理解了上面的命令行全过程后,我们就可以通过配置让 VS Code 帮我们“代劳”,实现F5 一键图形化调试

4.1 连接 WSL

  1. VScode必须安装 WSL 插件。
  2. 在 WSL 终端进入你的项目目录:cd ~/code
  3. 输入 code . 启动 VS Code。
  4. 看到 VS Code 左下角显示 WSL: Ubuntu 即表示连接成功。

4.2 配置 tasks.json (代替手工 GCC)

我们的目标是:按下 Ctrl+Shift+B 自动执行上面那串 gcc 编译命令。

在项目根目录创建 .vscode/tasks.json 文件,填入以下内容:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "GCC Build Active File",  // 任务标签,记注它,后面要用
            "type": "shell",
            "command": "/usr/bin/gcc",
            "args": [
                "-g",              // 必须有,否则无法调试
                "${file}",         // 当前打开的文件名
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}.out", // 输出为同名.out文件
                "-std=c11",
                "-Wall"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": ["$gcc"]
        }
    ]
}

4.3 配置 launch.json (代替手工 GDB)

我们的目标是:按下 F5,自动调用上面的编译任务,然后启动 GDB 图形化调试。

.vscode/launch.json 文件中填入以下内容:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "GDB Debug Active File",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}.out",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "为 GDB 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            // 关键!调试前先自动跑一遍上面的编译任务
            "preLaunchTask": "GCC Build Active File" 
        }
    ]
}

配置好后,你就可以用鼠标在行号左边打断点,按 F5 启动调试,在左侧栏实时查看变量值了!

5. 使用 CMake 管理多文件项目

对于单文件,gcc 足够了。但如果是多文件项目,手写 gcc main.c utils.c helper.c ... 会很痛苦。这时就该用 CMake

项目结构示例:

project/
├── CMakeLists.txt
├── main.c
└── utils.c

CMakeLists.txt 模板:

# CMake 最低版本要求
cmake_minimum_required(VERSION 3.16)
# 项目名称和语言
project(my_c_project C)
# 设置 C 语言标准
set(CMAKE_C_STANDARD 11)
# 添加可执行文件,源文件列表写在后面
add_executable(app main.c utils.c)

构建流程:

# 创建一个 build 文件夹存放编译产物
mkdir build && cd build
# 生成 Makefile
cmake ..
# 执行编译
make
# 或者用 cmake 命令
# cmake --build .

6. 避坑指南与总结

  1. 编译参数的选择 (-g-Wall): 再次强调 -g-Wall 的重要性。前者是 GDB 调试的入场券,后者能帮你提前发现无数低级错误(比如变量未初始化),省下大量调试时间。

  2. VS Code 配置核对: 按下 F5 提示 preLaunchTask 错误?检查 launch.json 里的 preLaunchTask 名字是否和 tasks.json 里的 label 完全一致

  3. 适当使用 “Code Runner” 插件: VS Code 的 Code Runner 插件虽然方便,但它隐藏了具体的编译命令,一键运行很爽,但对学习毫无帮助。建议在学习阶段手动敲终端命令或使用我们配置的 F5 调试流程,理解编译、链接的全过程。