前一篇文章中,我們講述了如何利用 VSCode 軟件來(lái)搭建一個(gè) C 語(yǔ)言的開(kāi)發(fā)環(huán)境,這個(gè) C 語(yǔ)言的開(kāi)發(fā)環(huán)境和我們之前《樂(lè)創(chuàng) C 語(yǔ)言教程》里面所講述的有很大差別,這些差別在我看來(lái)對(duì)于那些已經(jīng)了解 C 語(yǔ)言命令行編譯過(guò)程的童鞋來(lái)說(shuō)是一個(gè)福音,因?yàn)樗梢源蟠蟮厥∪ノ覀兠看尉幾g時(shí)需要輸入的命令。當(dāng)然,如果你一開(kāi)始學(xué)習(xí) C 語(yǔ)言就使用這樣省事的工具,對(duì)你自身了解 C 語(yǔ)言的編譯步驟以及文件依賴關(guān)系來(lái)說(shuō),并不是一件好事。所以,我也衷心希望剛剛接觸 C 語(yǔ)言的童鞋還是按照我們《樂(lè)創(chuàng) C 語(yǔ)言教程》里面所講述的工具來(lái)學(xué)習(xí) C 語(yǔ)言,等到了解了這些編譯的過(guò)程,再來(lái)搭建這個(gè) VSCode IDE。
VSCode 的預(yù)定義變量
我們上一篇文章中講述了如何將 MinGW 工具嵌入到 VSCode 文本編輯器中,在這個(gè)配置的過(guò)程中,我們只需要通過(guò)修改 VSCode 生成的“luanch.json”和“task.json”兩個(gè) JSON 文件中的特定字段,就可以實(shí)現(xiàn)開(kāi)發(fā)環(huán)境的搭建。那么這里可能就會(huì)有讀者疑惑了,這些字段既然是 VSCode 提供的,那么有沒(méi)有一張?jiān)敿?xì)羅列這些參數(shù)的表格,以備自己的不時(shí)之需。這個(gè)答案是肯定的,VSCode 編輯器的官網(wǎng)有相關(guān)的文檔專門來(lái)解釋這些 JSON 文檔中的關(guān)鍵字段,詳情可以參考 VSCode 官方文檔:
https://code.visualstudio.com/docs/editor/variables-reference。這里我們也來(lái)簡(jiǎn)單地講述下。
圖 1 task.json
如圖 1 所示的“task.json”中的內(nèi)容。這個(gè)文件中的后綴名是“.json”,關(guān)于“json”我們?cè)谶@里簡(jiǎn)單介紹下,JSON(JavaScript Object Notation, JS 對(duì)象簡(jiǎn)譜) 是一種輕量級(jí)的數(shù)據(jù)交換格式。它基于 ECMAScript (歐洲計(jì)算機(jī)協(xié)會(huì)制定的 js 規(guī)范)的一個(gè)子集,采用完全獨(dú)立于編程語(yǔ)言的文本格式來(lái)存儲(chǔ)和表示數(shù)據(jù)。簡(jiǎn)潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語(yǔ)言。
JSON 文件的內(nèi)容都是以“鍵 - 值對(duì)”的形式存在的,鍵值對(duì)是一種高級(jí)語(yǔ)言廣泛支持的符合數(shù)據(jù)類型,在某些高級(jí)語(yǔ)言中也被稱為“字典”,其內(nèi)部的每一個(gè)數(shù)據(jù)項(xiàng)的結(jié)構(gòu)為:
索引(鍵)”: “內(nèi)容(值)
在 VSCode 中,它提供兩個(gè)用以配置 VSCode 任務(wù)的文件,“launch.json”以及”tasks.json”。“launch.json”為調(diào)試配置文件,這里面指定了啟動(dòng)調(diào)試之后的調(diào)試器命令,以及調(diào)試之前的任務(wù)。這里我們可以將編譯任務(wù)在這里指出。
“task.json”為編譯任務(wù)配置文件,這里指出了編譯任務(wù)的命令以及具體參數(shù)。
再仔細(xì)觀察圖 1,我們發(fā)現(xiàn)其中很多字段對(duì)應(yīng)的變量是以“${變量名}”形式出現(xiàn)的,這些變量名其實(shí)在 VSCode 中是被事先定義好的,有點(diǎn)類似于我們操作系統(tǒng)中的環(huán)境變量,其中部分變量的具體解釋如下:
$ {workspaceFolder} - 在 VS Code 中打開(kāi)的文件夾的路徑
$ {workspaceFolderBasename} - 在 VS Code 中打開(kāi)的文件夾名稱,不帶任何斜杠(/)
$ {file} - 當(dāng)前打開(kāi)的文件
$ {fileWorkspaceFolder} - 當(dāng)前打開(kāi)的文件的工作區(qū)文件夾
$ {relativeFile} - 當(dāng)前相對(duì)于打開(kāi)的文件 workspaceFolder
$ {relativeFileDirname} - 當(dāng)前打開(kāi)的文件相對(duì)于的目錄名 workspaceFolder
$ {fileBasename} - 當(dāng)前打開(kāi)的文件的基本名稱
$ {fileBasenameNoExtension} - 當(dāng)前打開(kāi)的文件的基本名稱,沒(méi)有文件擴(kuò)展名
$ {fileDirname} - 當(dāng)前打開(kāi)的文件的目錄名
$ {fileExtname} - 當(dāng)前打開(kāi)的文件的擴(kuò)展名
$ {cwd} - 啟動(dòng)時(shí)任務(wù)運(yùn)行程序的當(dāng)前工作目錄
$ {lineNumber} - 活動(dòng)文件中當(dāng)前選擇的行號(hào)
$ {selectedText} - 活動(dòng)文件中的當(dāng)前選定文本
$ {execPath} - 正在運(yùn)行的 VS Code 可執(zhí)行文件的路徑
$ {defaultBuildTask} - 默認(rèn)構(gòu)建任務(wù)的名稱
$ {pathSeparator} - 操作系統(tǒng)用來(lái)分隔文件路徑中的組件的字符
編譯多個(gè)源文件
到目前為止,我們講述的 VSCode C 語(yǔ)言編譯器貌似還是只支持單一源文件的編譯。那么如果我有兩個(gè),三個(gè)甚至多個(gè)源文件的編譯,是不是需要像之前講述的那樣寫 Makefile?
要回答這個(gè)問(wèn)題,最好的辦法就是立即動(dòng)手寫代碼,我們可以在同一個(gè)文件夾中創(chuàng)建一個(gè)“a.c”和“a.h”文件,這個(gè)文件中只實(shí)現(xiàn)輸出一句“Hello world”的功能。定義好函數(shù)之后,我們?cè)?ldquo;main.c”文件中去包含這個(gè)“a.h”,接著去調(diào)用 a.h 中聲明的打印函數(shù),具體代碼如圖 2 所示。
圖 2 新增的“a.c”和“a.h”
//main.c
#include
#include "a.h"
int main(void) {
int number;
printf("input:n");
scanf("%d", &number);
printHello();
if((number > 1) && (number <= 100)) {
printf("Smalln");
} else if((number > 101) && (number <= 200)) {
printf("Middlen");
} else {
printf("Largen");
}
return 0;
}
//a.c
#include
#include "a.h"
void printHello(void) {
printf("Hello world");
}
//a.h
#ifndef __A_H_
#define __A_H_
void printHello(void);
#endif
然后,我們?cè)谏弦黄恼戮帉懙?ldquo;launch.json”和“task.json”文件基礎(chǔ)上進(jìn)行調(diào)試。結(jié)果 VSCode 拋出了如圖 3 所示的錯(cuò)誤。
圖 3 編譯輸出錯(cuò)誤
我們?cè)诮K端上可以看到其出錯(cuò)的原因,歸根到底是因?yàn)闆](méi)有找到“main.c”文件中的“printHello”函數(shù)定義,這個(gè)原因是因?yàn)榫幾g器其實(shí)是沒(méi)有編譯 a.c 這個(gè)源文件。那如何才能添加對(duì)這個(gè)源文件的編譯呢?我們?cè)僮屑?xì)來(lái)看下,終端提示的錯(cuò)誤中,在執(zhí)行 “D:softwaremingw64bingcc.exe '-g', 'C:Users1DesktopNumCalmain.c', '-o', 'C:Users1DesktopNumCalmain.exe'”語(yǔ)句時(shí)退出的,這句語(yǔ)句其實(shí)是我們?cè)?ldquo;task.json”文件中定義的。
圖 4 task.json
如圖 4 紅框中圈出的便是具體的編譯命令,因此我們?cè)谶@個(gè)編譯命令中只需要增加對(duì)“a.c”文件的編譯即可。如圖 5 所示,在原有的“task.json”文件基礎(chǔ)上,增加了對(duì)“a.c”文件的編譯。
圖 5 “task.json”中,增加對(duì) a.c 文件的編譯
//task.json
{
"version": "2.0.0",
"label": "C/C++: gcc.exe build active file",
"command": "gcc",
"args": [
"-g",
"${file}",
"${fileDirname}\a.c", // 增加對(duì) a.c 文件的編譯
"-o",
"${fileDirname}\${fileBasenameNoExtension}.exe"
],
"problemMatcher": [
"$gcc"
],
"group": "build",
"detail": "compiler: D:\software\mingw64\bin\gcc.exe",
}
//launch.json
{
// 使用 IntelliSense 了解相關(guān)屬性。
// 懸停以查看現(xiàn)有屬性的描述。
// 欲了解更多信息,請(qǐng)?jiān)L問(wèn): https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "build and debug", // 配置名稱,將會(huì)在啟動(dòng)配置的下拉菜單中顯示
"type": "cppdbg", // 配置類型,這里只能為 cppdbg
"request": "launch", // 請(qǐng)求配置類型,可以為 launch(啟動(dòng))或 attach(附加)
"program": "${fileDirname}/${fileBasenameNoExtension}.exe",
// 將要進(jìn)行調(diào)試的程序的路徑
"args": [], // 程序調(diào)試時(shí)傳遞給程序的命令行參數(shù),一般設(shè)為空即可
"stopAtEntry": false, // 設(shè)為 true 時(shí)程序?qū)和T诔绦蛉肟谔?,一般設(shè)置為 false
"cwd": "${fileDirname}", // 調(diào)試程序時(shí)的工作目錄,一般為${fileDirname}即代碼所在目錄
"environment": [],
"externalConsole": true, // 調(diào)試時(shí)是否顯示控制臺(tái)窗口,一般設(shè)置為 true 顯示控制臺(tái)
"MIMode": "gdb",
"miDebuggerPath": "D:/software/mingw64/bin/gdb.exe", // miDebugger 的路徑,注意這里要與 MinGw 的路徑對(duì)應(yīng)
"preLaunchTask": "gcc", // 這里需要添加一個(gè)參數(shù),
// 調(diào)試會(huì)話開(kāi)始前執(zhí)行的任務(wù),一般為編譯程序,c++為 g++, c 為 gcc
"setupCommands": [
{
"description": "為 gdb 啟用整齊打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
接著,我們切換回“main.c”,再點(diǎn)擊調(diào)試代碼,此時(shí) VSCode 就可以正常進(jìn)入調(diào)試界面了。如圖 6 所示。
圖 6 VSCode 調(diào)試界面