在 Visual Studio Code 中使用 Clang
在本教學課程中,您將在 macOS 上設定 Visual Studio Code 以使用 Clang/LLVM 編譯器與偵錯工具。
設定完 VS Code 後,您將在 VS Code 中編譯並偵錯 C++ 程式。本教學課程不會教授 Clang 或 C++ 語言本身的知識。關於這些主題,網路上有許多優質的資源可供參考。
如果您遇到任何問題,歡迎隨時在 VS Code 文件儲存庫中為本教學課程提出問題。
先決條件
若要成功完成本教學課程,您必須執行下列步驟
-
安裝 VS Code 的 C++ 擴充功能。您可以透過在擴充功能檢視中搜尋「C++」來安裝 C/C++ 擴充功能(⇧⌘X (Windows, Linux Ctrl+Shift+X))。

確保 Clang 已安裝
您的 Mac 可能已經安裝了 Clang。若要驗證,請開啟 macOS 終端機視窗並輸入下列指令
clang --version
如果尚未安裝 Clang,請輸入下列指令來安裝包含 Clang 的命令列開發人員工具
xcode-select --install
建立 Hello World 應用程式
從 macOS 終端機,建立一個名為 projects 的空資料夾,用來存放您所有的 VS Code 專案,然後建立一個名為 helloworld 的子資料夾,進入該資料夾,並透過在終端機視窗中輸入下列指令來開啟 VS Code
mkdir projects
cd projects
mkdir helloworld
cd helloworld
code .
code . 指令會在目前的作業資料夾中開啟 VS Code,這將成為您的「工作區」。隨著您完成本教學課程,工作區的 .vscode 資料夾中會建立三個檔案
tasks.json(編譯器建置設定)launch.json(偵錯工具設定)c_cpp_properties.json(編譯器路徑與 IntelliSense 設定)
新增一個 Hello World 原始程式碼檔案
在檔案總管標題列中,選取新增檔案按鈕,並將檔案命名為 helloworld.cpp。

貼上以下原始碼
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"};
for (const string& word : msg)
{
cout << word << " ";
}
cout << endl;
}
現在按下 ⌘S (Windows, Linux Ctrl+S) 來儲存檔案。請注意,您的檔案會列在 VS Code 側邊欄的檔案總管檢視中(⇧⌘E (Windows, Linux Ctrl+Shift+E))。

您也可以透過選取檔案 > 自動儲存來啟用自動儲存,以便自動儲存檔案變更。您可以在 VS Code 使用者介面文件中進一步了解其他檢視方式。
注意:當您儲存或開啟 C++ 檔案時,您可能會看到 C/C++ 擴充功能關於 Insiders 版本可用性的通知,這讓您可以測試新功能與修正。您可以選取
X(清除通知)來忽略此通知。
探索 IntelliSense
IntelliSense 是一個能協助您更快速、更有效率地進行編寫程式碼的工具,它提供程式碼完成、參數資訊、快速資訊與成員清單等程式碼編輯功能。
若要查看 IntelliSense 的運作,請將滑鼠懸停在 vector 或 string 上以查看其型別資訊。如果您在第 10 行輸入 msg.,您會看到一份建議的成員函式完成清單,這些都是由 IntelliSense 所產生的。

您可以按下 Tab 鍵來插入選取的成員。接著,當您新增開頭括號時,系統會顯示該函式所需參數的相關資訊。
如果尚未設定 IntelliSense,請開啟命令選擇區(⇧⌘P (Windows, Linux Ctrl+Shift+P))並輸入選取 IntelliSense 設定。從編譯器下拉式選單中,選取 Use clang++ 進行設定。更多資訊請參閱 IntelliSense 設定文件。
執行 helloworld.cpp
請記住,C++ 擴充功能使用您安裝在電腦上的 C++ 編譯器來建置程式。在嘗試於 VS Code 中執行及偵錯 helloworld.cpp 之前,請務必先安裝好 C++ 編譯器(如 Clang)。
-
開啟
helloworld.cpp使其成為作用中檔案。 -
按下編輯器右上角的執行按鈕。

-
從系統偵測到的編譯器清單中,選擇 C/C++: clang++ 建置並偵錯作用中檔案。

您僅在首次執行 helloworld.cpp 時才會被要求選擇編譯器。此編譯器會成為 tasks.json 檔案中設定的「預設」編譯器。
-
建置成功後,您的程式輸出將會出現在整合式的偵錯主控台中。

恭喜!您已成功在 VS Code 中執行您的第一個 C++ 程式!
了解 tasks.json
當您第一次執行程式時,C++ 擴充功能會在專案的 .vscode 資料夾中建立 tasks.json。tasks.json 用於儲存建置設定。
以下是 macOS 上 tasks.json 檔案的範例
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: clang++ build active file",
"command": "/usr/bin/clang++",
"args": [
"-fcolor-diagnostics",
"-fansi-escape-codes",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}
注意:您可以在 變數參考中進一步了解
tasks.json變數。
command 設定指定要執行的程式。在此案例中,即為 clang++。
args 陣列指定傳遞給 clang++ 的命令列參數。這些參數必須依照編譯器預期的順序指定。
此任務指示 C++ 編譯器使用作用中檔案 (${file}),對其進行編譯,並在目前目錄 (${fileDirname}) 中建立一個輸出檔案 (-o 開關),其名稱與作用中檔案相同但沒有副檔名 (${fileBasenameNoExtension})。此過程會建立 helloworld。
label 值是您在任務清單中看到的名稱,可依個人喜好設定。
detail 值是任務清單中任務的說明。您可以修改此字串以與類似的任務區別。
problemMatcher 值選擇用於在編譯器輸出中尋找錯誤與警告的輸出剖析器。對於 clang++,$gcc 問題比對器能產生最佳結果。
從現在起,執行按鈕將始終從 tasks.json 讀取以判斷如何建置並執行您的程式。您可以在 tasks.json 中定義多個建置任務,而執行按鈕會使用標記為預設的任務。若您需要變更預設編譯器,可以在命令選擇區執行任務:設定預設建置任務。或者,您可以修改 tasks.json 檔案並透過取代此區段來移除預設值
"group": {
"kind": "build",
"isDefault": true
},
取代為
"group": "build",
修改 tasks.json
您可以修改 tasks.json 以建置多個 C++ 檔案,使用 "${workspaceFolder}/*.cpp" 作為參數,而不是 "${file}"。這會建置您目前資料夾中的所有 .cpp 檔案。您也可以透過將 "${fileDirname}/${fileBasenameNoExtension}" 取代為硬編碼的檔名(例如 "${workspaceFolder}/myProgram.out")來修改輸出檔名。
偵錯 helloworld.cpp
若要偵錯您的程式碼:
-
回到
helloworld.cpp使其成為作用中檔案。 -
透過點擊編輯器邊緣或在目前行按下 F9 來設定中斷點。

-
從執行按鈕旁的下拉式選單中,選取 偵錯 C/C++ 檔案。

-
從系統偵測到的編譯器清單中選擇 C/C++: clang++ 建置並偵錯作用中檔案(您僅在第一次執行或偵錯
helloworld.cpp時才會被要求選擇編譯器)。
-
您將看到任務執行,並將輸出列印到終端機視窗中。

執行按鈕有兩種模式:執行 C/C++ 檔案與 偵錯 C/C++ 檔案。預設值為上次使用的模式。如果您在執行按鈕中看到偵錯圖示,您可以直接選取執行按鈕來進行偵錯,而不必選取下拉式選單項目。
探索偵錯器
在開始逐步執行程式碼之前,讓我們花點時間留意使用者介面的幾項變更
-
整合式終端機會出現在原始程式碼編輯器的底部。在偵錯主控台索引標籤中,您可以看到指出偵錯工具已啟動並執行的輸出。
-
編輯器會反白顯示您在啟動偵錯工具前設定中斷點的那一行。

-
活動列中的執行與偵錯檢視會顯示偵錯資訊。
-
在程式碼編輯器的頂部,會出現一個偵錯控制面板。您可以透過抓取左側的點將其移至畫面其他位置。

逐步執行程式碼
現在您已準備好開始逐步執行程式碼。
-
選取偵錯控制面板中的逐步跳過 (Step over) 圖示,使
for (const string& word : msg)陳述式被反白顯示。
逐步跳過指令會跳過在建立並初始化
msg變數時所觸發的vector與string類別內部的所有函式呼叫。請注意變數視窗中的變化。由於該陳述式已完成,msg的內容現在可見。 -
再次按下逐步跳過以前進到下一個陳述式(跳過初始化迴圈所執行的所有內部程式碼)。現在,變數視窗會顯示關於迴圈變數的資訊。
-
再次按下逐步跳過以執行
cout陳述式。 -
如果您願意,可以持續按下逐步跳過,直到向量中的所有單字都列印到主控台為止。但如果您感到好奇,請嘗試按下逐步執行 (Step Into) 按鈕,以逐步追蹤 C++ 標準函式庫中的原始程式碼!
設定監看式 (Watch)
您可能希望在程式執行時持續追蹤某個變數的值。您可以透過對該變數設定監看式 (Watch) 來達成。
-
在監看式視窗中,選取加號並在文字方塊中輸入
word。這是迴圈變數的名稱。現在,當您逐步執行迴圈時,請觀察監看式視窗。
注意:監看變數的值僅在程式執行範圍位於該變數的作用域內時才可用。例如,對於迴圈變數,其值僅在程式執行迴圈時才可用。
-
在迴圈前新增此陳述式以增加另一個監看式:
int i = 0;。然後在迴圈內新增此陳述式:++i;。現在,像前一步驟那樣,為i新增監看式。 -
當執行暫停時,您可以將滑鼠指標懸停在任何變數上,以快速查看其值。

使用 launch.json 自訂偵錯
當您使用執行按鈕或 F5 進行偵錯時,C++ 擴充功能會即時建立動態偵錯設定。
在某些情況下,您會希望自訂偵錯設定,例如指定在執行階段傳遞給程式的參數。您可以在 launch.json 檔案中定義自訂偵錯設定。
若要建立 launch.json,請從執行按鈕下拉式選單中選擇 新增偵錯設定。

接著,您將看到各類預先定義偵錯設定的下拉式選單。選擇 C/C++: clang++ 建置並偵錯作用中檔案。
VS Code 會建立一個 launch.json 檔案,看起來會像這樣
{
"configurations": [
{
"name": "C/C++: clang++ build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"preLaunchTask": "C/C++: clang++ build active file"
}
],
"version": "2.0.0"
}
program 設定指定了您想要偵錯的程式。此處設定為作用中檔案資料夾 ${fileDirname} 與作用中檔名 ${fileBasenameNoExtension};若 helloworld.cpp 為作用中檔案,則結果會是 helloworld。args 屬性是一個陣列,用於在執行階段傳遞參數給程式。
依預設,C++ 擴充功能不會在您的原始程式碼中新增任何中斷點,且 stopAtEntry 值預設為 false。
將 stopAtEntry 值變更為 true,以讓偵錯工具在您開始偵錯時於 main 方法停下。
確保 preLaunchTask 值與 tasks.json 檔案中建置任務的 label 相符。
從現在起,當您啟動程式進行偵錯時,執行按鈕與 F5 都會讀取您的
launch.json檔案。
新增額外的 C/C++ 設定
如需更進階的 C/C++ 擴充功能控制,請建立 c_cpp_properties.json 檔案,這讓您可以變更編譯器路徑、包含路徑 (Include paths)、要編譯的 C++ 標準 (如 C++17) 等設定。
透過從命令選擇區(⇧⌘P (Windows, Linux Ctrl+Shift+P))執行C/C++: 編輯設定 (UI) 指令,來檢視 C/C++ 設定 UI。

這將開啟 C/C++ 設定頁面。

Visual Studio Code 會將這些設定放置在 .vscode/c_cpp_properties.json。如果您直接開啟該檔案,它應該會長得像這樣
{
"configurations": [
{
"name": "Mac",
"includePath": ["${workspaceFolder}/**"],
"defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "macos-clang-arm64"
}
],
"version": 4
}
僅當您的程式包含不在您的工作區或標準函式庫路徑中的標頭檔時,才需要修改包含路徑 (Include path) 設定。
編譯器路徑
擴充功能使用 compilerPath 設定來推斷 C++ 標準函式庫標頭檔的路徑。當擴充功能知道去哪裡尋找這些檔案時,它就能提供智慧補全與移至定義導覽等功能。
C/C++ 擴充功能會嘗試根據系統上找到的內容,以預設編譯器位置填入 compilerPath。compilerPath 的搜尋順序為
- 針對已知編譯器名稱的 PATH。編譯器在清單中出現的順序取決於您的 PATH。
- 接著會搜尋硬編碼的 Xcode 路徑,例如
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/
更多資訊請參閱 IntelliSense 設定文件。
Mac Framework 路徑
在 C/C++ 設定畫面上,向下捲動並展開進階設定,並確保Mac Framework 路徑指向系統標頭檔。例如:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks
疑難排解
編譯與連結錯誤
造成錯誤(例如 undefined _main,或 attempting to link with file built for unknown-unsupported file format 等)最常見的原因,是您在開始建置或偵錯時,helloworld.cpp 並非作用中檔案。這是因為編譯器嘗試編譯非原始程式碼的內容,例如您的 launch.json、tasks.json 或 c_cpp_properties.json 檔案。
如果您看到提及「C++11 擴充功能」的建置錯誤,可能是因為您沒有將 tasks.json 建置任務更新為使用 clang++ 參數 --std=c++17。預設情況下,clang++ 使用 C++98 標準,該標準不支援 helloworld.cpp 中使用的初始化方式。請務必將 tasks.json 檔案的所有內容取代為 執行 helloworld.cpp 章節中提供的程式碼區塊。
終端機無法啟動以接收輸入
在 macOS Catalina 及更新版本上,您可能會遇到即使已設定 "externalConsole": true,仍無法輸入資料的問題。終端機視窗會開啟,但無法輸入任何資料。
此問題目前追蹤於 #5079。
解決方法是讓 VS Code 啟動一次終端機。您可以透過在 tasks.json 中新增並執行此任務來達成
{
"label": "Open Terminal",
"type": "shell",
"command": "osascript -e 'tell application \"Terminal\"\ndo script \"echo hello\"\nend tell'",
"problemMatcher": []
}
您可以透過終端機 > 執行任務... 並選擇 開啟終端機來執行此特定任務。
一旦您接受權限要求,進行偵錯時外部主控台應該就會正常顯示。
後續步驟
- 探索 VS Code 使用者指南。
- 查看 C++ 擴充功能總覽
- 建立新的工作區,將您的 .json 檔案複製到其中,為新的工作區路徑、程式名稱等調整必要的設定,然後開始編寫程式碼吧!