參加你附近的 ,瞭解 VS Code 中的 AI 輔助開發。

在 Visual Studio Code 中使用 Clang

在本教程中,您將在 macOS 上配置 Visual Studio Code 以使用 Clang/LLVM 編譯器和偵錯程式。

配置 VS Code 後,您將在 VS Code 中編譯和除錯一個 C++ 程式。本教程不教授 Clang 或 C++ 語言。對於這些主題,網上有許多很好的資源。

如果您遇到任何問題,請隨時在 VS Code 文件庫中為本教程提交問題。

先決條件

要成功完成本教程,你必須執行以下步驟

  1. macOS 上安裝 Visual Studio Code

  2. 安裝 VS Code 的 C++ 擴充套件。您可以在“擴充套件”檢視 (⇧⌘X (Windows, Linux Ctrl+Shift+X)) 中搜索“C++”來安裝 C/C++ 擴充套件。

    C/C++ extension

確保 Clang 已安裝

Clang 可能已經安裝在您的 Mac 上。要驗證它是否已安裝,請開啟一個 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

New File title bar button

貼上以下原始碼

#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)) 中。

File Explorer

您還可以透過選擇**檔案** > **自動儲存**來啟用自動儲存,以自動儲存您的檔案更改。您可以在 VS Code 使用者介面文件中瞭解有關其他檢視的更多資訊。

注意:當你儲存或開啟 C++ 檔案時,你可能會看到來自 C/C++ 擴充套件的關於 Insiders 版本可用性的通知,該版本可讓你測試新功能和修復。你可以透過選擇 X清除通知)來忽略此通知。

探索 IntelliSense

IntelliSense 是一個工具,透過新增程式碼完成、引數資訊、快速資訊和成員列表等程式碼編輯功能,幫助您更快、更高效地編寫程式碼。

要檢視 IntelliSense 的實際效果,請將滑鼠懸停在 vectorstring 上以檢視其型別資訊。如果您在第 10 行鍵入 msg.,您可以看到一個推薦呼叫的成員函式的完成列表,這些都是由 IntelliSense 生成的。

Statement completion IntelliSense

您可以按 Tab 鍵插入所選成員。然後,當您新增左括號時,將顯示有關該函式所需引數的資訊。

如果 IntelliSense 尚未配置,請開啟命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 並輸入**選擇 IntelliSense 配置**。從編譯器下拉列表中,選擇 Use clang++ 進行配置。更多資訊可以在 IntelliSense 配置文件中找到。

執行 helloworld.cpp

請記住,C++ 擴充套件使用您在計算機上安裝的 C++ 編譯器來構建您的程式。在嘗試在 VS Code 中執行和除錯 helloworld.cpp 之前,請確保您已安裝 C++ 編譯器(如 Clang)。

  1. 開啟 helloworld.cpp,使其成為活動檔案。

  2. 單擊編輯器右上角的播放按鈕。

    Screenshot of helloworld.cpp and play button

  3. 從系統上檢測到的編譯器列表中選擇 **C/C++: clang++ build and debug active file**。

    Build and debug task

只有在第一次執行 helloworld.cpp 時,系統才會要求您選擇編譯器。此編譯器將是 tasks.json 檔案中設定的“預設”編譯器。

  1. 構建成功後,您的程式輸出將出現在整合的**除錯控制檯**中。

    screenshot of program output

恭喜!您剛剛在 VS Code 中運行了您的第一個 C++ 程式!

理解 tasks.json

當您第一次執行程式時,C++ 擴充套件會建立 tasks.json,它位於您專案的 .vscode 資料夾中。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}) 中建立一個與活動檔案同名但沒有副檔名 (${fileBasenameNoExtension}) 的輸出檔案 (-o 開關)。此過程會建立 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

要除錯你的程式碼,

  1. 回到 helloworld.cpp,使其成為活動檔案。

  2. 透過單擊編輯器邊欄或在當前行上按 F9 來設定斷點。

    screenshot of breakpoint in helloworld.cpp

  3. 從播放按鈕旁邊的下拉選單中,選擇**除錯 C/C++ 檔案**。

    Screenshot of play button drop-down

  4. 從系統上檢測到的編譯器列表中選擇 **C/C++: clang++ build and debug active file**(只有在第一次執行或除錯 helloworld.cpp 時,您才會被要求選擇編譯器)。

    Build and debug task

  5. 您將看到任務執行,並將輸出列印到**終端**視窗。

    Hello World Terminal Output

播放按鈕有兩種模式:**執行 C/C++ 檔案**和**除錯 C/C++ 檔案**。預設是上次使用的模式。如果您在播放按鈕中看到除錯圖示,您可以選擇播放按鈕進行除錯,而無需選擇下拉選單項。

探索偵錯程式

在開始單步除錯程式碼之前,我們花點時間注意使用者介面中的幾處變化

  • 整合終端出現在原始碼編輯器的底部。在**除錯控制檯**選項卡中,您會看到指示偵錯程式已啟動並正在執行的輸出。

  • 編輯器會高亮顯示你在啟動偵錯程式之前設定斷點的行

    Initial breakpoint

  • 活動欄中的**執行和除錯**檢視顯示除錯資訊。

  • 程式碼編輯器頂部會出現一個除錯控制面板。你可以透過抓取左側的點來在螢幕上移動它。

    Debugging controls

單步除錯程式碼

現在你已準備好開始單步除錯程式碼。

  1. 在除錯控制面板中選擇**單步跳過**圖示,使 for (const string& word : msg) 語句高亮顯示。

    Step over button

    **單步跳過**命令會跳過在建立和初始化 msg 變數時呼叫的 vectorstring 類中的所有內部函式呼叫。請注意**變數**視窗中的變化。msg 的內容是可見的,因為該語句已經完成。

  2. 再次按**單步跳過**以進入下一條語句(跳過為初始化迴圈而執行的所有內部程式碼)。現在,**變數**視窗顯示有關迴圈變數的資訊。

  3. 再次按**單步跳過**以執行 cout 語句。

  4. 如果你願意,可以繼續按單步跳過,直到向量中的所有單詞都列印到控制檯。但如果你好奇,可以嘗試按單步進入按鈕來單步執行 C++ 標準庫中的原始碼!

設定監視

您可能希望在程式執行時跟蹤變數的值。您可以透過對變數設定**監視**來實現這一點。

  1. 在**監視**視窗中,選擇加號並在文字框中鍵入 word。這是迴圈變數的名稱。現在,在單步執行迴圈時檢視**監視**視窗。

    Watch window

    注意:監視變數的值僅在程式執行位於該變數的作用域內時才可用。例如,對於迴圈變數,其值僅在程式執行迴圈時才可用。

  2. 透過在迴圈前新增此語句來新增另一個監視:int i = 0;。然後,在迴圈內部新增此語句:++i;。現在,像上一步一樣為 i 新增監視。

  3. 當執行暫停時,您可以用滑鼠指標懸停在任何變數上以快速檢視其值。

    Mouse hover

使用 launch.json 自定義除錯

當你使用播放按鈕或 F5 進行除錯時,C++ 擴充套件會即時建立一個動態除錯配置。

在某些情況下,你可能希望自定義除錯配置,例如指定在執行時傳遞給程式的引數。你可以在 launch.json 檔案中定義自定義除錯配置。

要建立 launch.json,請從播放按鈕下拉選單中選擇新增除錯配置

Add debug configuration play button menu

然後您會看到一個包含各種預定義除錯配置的下拉列表。選擇 **C/C++: clang++ build and debug active file**。 C++ 除錯配置下拉列表

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 是活動檔案,這將是 helloworldargs 屬性是在執行時傳遞給程式的引數陣列。

預設情況下,C++ 擴充套件不會在您的原始碼中新增任何斷點,並且 stopAtEntry 的值被設定為 false

stopAtEntry 值更改為 true,以便在開始除錯時讓偵錯程式在 main 方法處停止。

請確保 preLaunchTask 的值與 tasks.json 檔案中構建任務的 label 相匹配。

從現在開始,播放按鈕和 F5 在啟動程式進行除錯時將從你的 launch.json 檔案中讀取資訊。

新增額外的 C/C++ 設定

要對 C/C++ 擴充套件進行更多控制,請建立一個 c_cpp_properties.json 檔案,該檔案允許您更改諸如編譯器路徑、包含路徑、編譯時使用的 C++ 標準(如 C++17)等設定。

透過從命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 執行命令 **C/C++: 編輯配置 (UI)** 來檢視 C/C++ 配置 UI。

Command Palette

這將開啟 **C/C++ 配置**頁面。

C++ configuration

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
}

只有當您的程式包含不在您的工作區或標準庫路徑中的標頭檔案時,您才需要修改**包含路徑**設定。

編譯器路徑

擴充套件使用 compilerPath 設定來推斷 C++ 標準庫標頭檔案的路徑。當擴充套件知道在哪裡可以找到這些檔案時,它就可以提供諸如智慧補全和**轉到定義**導航等功能。

C/C++ 擴充套件會根據在您系統上找到的內容,嘗試使用預設編譯器位置來填充 compilerPathcompilerPath 的搜尋順序是:

  • 您的 PATH 中已知編譯器的名稱。編譯器在列表中出現的順序取決於您的 PATH。
  • 然後搜尋硬編碼的 Xcode 路徑,例如 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/

更多資訊,請參閱 IntelliSense 配置文件

Mac 框架路徑

在 C/C++ 配置螢幕上,向下滾動並展開**高階設定**,並確保 **Mac 框架路徑**指向系統標頭檔案。例如:/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.jsontasks.jsonc_cpp_properties.json 檔案。

如果您看到提及“C++11 extensions”的構建錯誤,您可能沒有更新您的 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": []
}

您可以使用**終端** > **執行任務...** 並選擇**開啟終端**來執行此特定任務。

一旦您接受許可權請求,那麼當您除錯時,外部控制檯就應該會出現。

後續步驟