# VS Code調試C/C++程序
[toc]
記錄用VS Code調試C/C++程序的基本流程,加深對工程構建、編譯鏈接的理解。我自己目前的體會是不適合在實際工程中使用,除非對makefile工程構建、C/C++相關的工具鏈有深刻的認識,否則很難駕馭。
## 搭建VS Code C/C++調試環境
按照《參考1》搭建VS Code C/C++調試環境,大致的流程如下,
1. 安裝VS CODE
VSCODE是微軟免費的跨平臺的開發平臺框架,從其官網下載安裝即可;
2. 安裝微軟的C/C++插件
* 打開VS Code.
* 單擊左側工具欄的擴展圖標
* 搜索c++.
* 點擊安裝, 軟后重啟VSCODE.

插件安裝以后,打開一個包含C/C++源碼的文件夾時,VSCODE會自動添加一個包含設置文件的子目錄.vscode
> 注意,微軟的C/C++插件并不包含C++編譯器和調試器,這些需要自己安裝,比較常用的C++編譯器有Windows下的mingw-w64、macOS下的Clang for XCode和linux下的GCC,Windows需要把工具鏈的安裝地址添加至環境變量PATH里。
3. 配置IntelliSense
打開相關文件夾后,微軟的C/C++插件會根據系統的編譯器嘗試提供基本的配置,如果沒有成功配置,就需要自己生成一個配置文件c_cpp_properties.json,方法如下:
* 打開命令面板(Ctrl+Shift+P或菜單[查看]->[命令面板])
* 運行命令C/Cpp: Edit configurations...
* 生成c_cpp_properties.json,該配置文件保存于.vscode文件夾下
以下是基于Windows下MinGW C++編譯器生成的默認配置文件c_cpp_properties.json.
```
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "",
"compilerPath": "C:\\MinGW\\bin\\gcc.exe",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
```
4. Build代碼
如果你想build代碼,你需要配置task.json文件:
* 打開命令面板(Ctrl+Shift+P或菜單[查看]->[命令面板])
* 選擇命令Tasks: Configure Tasks...,單擊創建文件tasks.json,你會看到一系列任務運行模板
* 選擇模板Others :運行任意外部命令的示例
* 修改command命令行表達式,以build代碼,如g++
* 添加需要的args(如-g用來調試)
* 修改label,使其有描述性
tasks.json示例代碼,如下:
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello world",
"type": "shell",
"command": "g++",
"args": [
"-g", "helloworld.cpp"
]
}
]
}
```
如果你想通過菜單[任務]->[運行生成任務...]或快捷鍵(Ctrl+shift+B)build代碼,需要在剛才的文件tasks.json添加組build,如下,這樣就可以build代碼生成可執行的文件了:
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello world",
"type": "shell",
"command": "g++",
"args": [
"-g", "helloworld.cpp"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
```
5. 調試代碼
調試,需要生成文件launch.json:
* 點擊左側工具欄的調試圖標
* 在Debug視圖,點擊Configure圖標
* 選擇C++ (GDB/LLDB),生成文件launch.json,有兩個配置項
* C++ Launch 定義當你啟動調試加載你的應用時的屬性
* C++ Attach 定義已經運行進程的附加屬性
* 更新program屬性,添加自己的調試目錄
* 如果你想在調試之前build自己的代碼,需要添加preLaunchTask屬性,該屬性的內容為剛才在task.json中創建的任務的label(如之前的 "build hello world")
以下是用MinGW GDB調試器的launch.json配置文件的內容:
```
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "C:\\mingw\\bin\\gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build hello world"
}
]
}
```
至此,點擊左側工具欄的調試圖標,再點擊綠色的運行圖標,就能build代碼->調試程序了,這時,在終端已經可以看到“hello world”了!
## 一個簡單的C/C++程序調試
沒有實踐的理論就是空中樓閣。
1. 新建并打開一個源碼文件結構
* 新建一個目錄ex
* 目錄下新建文件hello.cpp,如下:
```
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("hello world!\n");
printf("hello world!\n");
getchar();
return 0;
}
```
* 打開VSCODE,[File]->[Open Folder]打開文件夾
2. 配置IntelliSense
打開命令面板(Ctrl+Shift+P或菜單[查看]->[命令面板]),運行命令C/Cpp: Edit configurations...,生成c_cpp_properties.json,該配置文件保存于.vscode文件夾下,以下是基于linux下GCC編譯器生成的默認配置文件c_cpp_properties.json:
```
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/clang++-3.5",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
```
> 需要關注的有兩項,"includePath"為包含文件的目錄,根據源碼結構自行設置,由于該源碼就一個hello.cpp文件,不用設置,默認的即可;"compilerPath"為編譯器的目錄,根據需要修改
3. Build代碼
* 新建build任務,這個任務的作用是提供編譯鏈接的腳本,個人理解,執行這個任務后會在本地目錄生成目標文件
* 菜單[Tasks]->[Run Build Task...],此時會提示沒有找到Build任務,是否需要去配置Build任務,只能跟著去做任務了,創建一個以Others為模板的Build任務配置文件tasks.json如下,
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello", // 起個自己喜歡的名字
"type": "shell",
"command": "g++", // 編譯的命令
"args": [ // 編譯命令的參數,會不會下就看會不會這些編譯命令的使用了
"-g", "ex.cpp", "-o", "qb.out"
],
// 以上是以Others為模板的Build任務配置文件tasks.json的內容
// 菜單[Tasks]->[Run Build Task...],還是提示在build hello工程里沒有build任務,按提示配置即生成如下配置內容
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
```
* 菜單[Tasks]->[Run Build Task...],執行以上配置的編譯鏈接的任務,其實就是執行了一條編譯命令
> g++ -g ex.cpp -o qb.out
這時可以在目錄下發現生成的目標文件qb.out
4. 調試代碼
* 點擊左側工具欄的調試圖標->Configure圖標->選擇C++ (GDB/LLDB),生成文件launch.json,
```
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/qb.out", // 輸出文件
"args": [],
"stopAtEntry": false, // 開始調試時,是否停在程序入口
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb", // 調試命令
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
// 以下是另添加,作用是調試前的的任務,下面定義的是之前定義的那個build任務
"preLaunchTask": "build hello"
}
]
}
```
* 點擊綠色的運行圖標即可調試,OK!
## Makefile構建的C/C++程序調試
VS Code 配合 Makefile 來提高 C/C++ 工程的可移植性,這個方案的思路是:使用 Makefile 來構建工程, VS Code 通過 Tasks 調用 make 工具來編譯,通過調用 gdb 來調試。其優點在于不是過分依賴 VS Code 自身的配置,一個合適的 Makefile 可以在各個平臺上執行編譯,但是在開發過程中又可以用到 VS Code 自身的插件帶來的便利,減少命令輸入,減少命令行 gdb 調試帶來的煩惱。
* **準備工作**
準備一套 Makefile 模板,比如說 https://github.com/TheNetAdmin/Makefile-Templates ,或者也可以自行寫一套模板,一個好的 Makefile 模板可以省去很多麻煩;
安裝編譯工具與 make 工具:尤其是在 Windows 下,使用 make 是一個比較麻煩的事情,推薦大家使用 msys 提供的一套工具,這里有一個打包供下載 https://pan.baidu.com/s/1kV5hx3p
1. 首先構建一個 Makefile ,如果沒有合適的可以到這里找到一些現成模板
這里的makefile文件,如下:
```
# originating https://github.com/TheNetAdmin/Makefile-Templates
# tool marcros
CC := g++
CCFLAG := -std=c++14
DBGFLAG := -g
CCOBJFLAG := $(CCFLAG) -c
# path marcros
BIN_PATH := bin
OBJ_PATH := obj
SRC_PATH := src
DBG_PATH := debug
# compile marcros
TARGET_NAME := main
ifeq ($(OS),Windows_NT)
TARGET_NAME := $(addsuffix .exe,$(TARGET_NAME))
endif
TARGET := $(BIN_PATH)/$(TARGET_NAME)
TARGET_DEBUG := $(DBG_PATH)/$(TARGET_NAME)
MAIN_SRC := src/main.cpp
# src files & obj files
SRC := $(foreach x, $(SRC_PATH), $(wildcard $(addprefix $(x)/*,.c*)))
OBJ := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
OBJ_DEBUG := $(addprefix $(DBG_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
# clean files list
DISTCLEAN_LIST := $(OBJ) \
$(OBJ_DEBUG)
CLEAN_LIST := $(TARGET) \
$(TARGET_DEBUG) \
$(DISTCLEAN_LIST)
# default rule
default: all
# non-phony targets
$(TARGET): $(OBJ)
$(CC) $(CCFLAG) -o $@ $?
$(OBJ_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAG) -o $@ $<
$(DBG_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAG) $(DBGFLAG) -o $@ $<
$(TARGET_DEBUG): $(OBJ_DEBUG)
$(CC) $(CCFLAG) $(DBGFLAG) $? -o $@
# phony rules
.PHONY: all
all: $(TARGET)
.PHONY: debug
debug: $(TARGET_DEBUG)
.PHONY: clean
clean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(CLEAN_LIST)
.PHONY: distclean
distclean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(DISTCLEAN_LIST)
```
2. 根據這個 Makefile,構建一個目錄結構如下的工程目錄
```
- Project
- Makefile
- src: 所有源文件 (不得放在子目錄)
- add.cpp
- add.h
- sub.cpp
- sub.h
- main.cpp
- obj
- 空
- debug
- 空
- bin
- 空
```
4. 然后對于 VS Code 的 tasks.json 和 launch.json 做一些修改
文件tasks.json
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "make",
"args": [
"default"
],
"type": "shell"
},
{
"label": "build-debug",
"command": "make",
"args": [
"debug"
],
"type": "shell"
},
{
"label": "clean",
"command": "make",
"args": [
"clean"
],
"type": "shell"
}
]
}
```
文件launch.json
```
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
// 修改為新的測試目標文件路徑
"program": "${workspaceRoot}/debug/main",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
//"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build-debug"
}
]
}
```
到此可以按上節的步驟使用編譯和調試工具了。
## STM32嵌入式程序調試
參考[使用VSCode和VS2017編譯調試STM32程序](https://www.cnblogs.com/WeyneChen/p/8379214.html),能下載運行,不能正常調試。

也許是JLINK不是正版造成的,也許是哪沒設置正確,以后再整。
## 參考資料
* 參考1:[C/C++ for VS Code (Preview)之官方文檔](https://code.visualstudio.com/docs/languages/cpp)
* 參考2:[VS Code 配置 C/C++ 環境](https://blog.csdn.net/wzxlovesy/article/details/76708151)
* 參考3:[使用VSCode和VS2017編譯調試STM32程序](https://www.cnblogs.com/WeyneChen/p/8379214.html)