Visual Studio Code 構建 C/C++ 開發環境
1. 安裝 MinGW Distro / MinGW / GNU GCC 中的任何一款 (其各類安裝文件分類為:x86_64 為64位版,i686 為32位版。win32 為Windows版,posix 為Windows+Linux版。sjlj 為傳統穩定版,seh 為高速版。所以,一般下載 x86_64-posix-seh 文件即可),( Windows 下的 VS Code 暫不支持 CLang )。
2. 安裝 VS Code
3. Ctrl + Shift + X 安裝 C/C++ (cpptools) 插件
4. Ctrl + Shift + X 安裝 Code Runner 插件
5. 重啟 VS Code,讓安裝的插件生效
6. 在操作系統中新建一個工程目錄,如 “cppProject”,然后啟動 VS Code,打開這個空目錄
7. 用 VS Code 在 cppProject 目錄新建一個源文件 hello.cpp
8. 添加頭文件索引路徑
在 hello.cpp 中,你會發現 include 頭文件那一行下面有綠色的波浪線,代表 VS Code 的 C/C++ 插件找不到頭文件的相應路徑。 將鼠標移到這一行點擊,會出現一個提示的黃色小燈泡符號,點擊它,然后點擊“Edit "includePath" setting”按鈕, 將生成並打開 c_cpp_properties.json 文件,編輯這個json文件,添加 C/C++ 頭文件的路徑進去。 這里 MinGW 的頭文件路徑為: “C:/MinGW/include/*”,將它添加到“includePath”和"browse/path"變量中。
{ "configurations": [ { "name": "Mac", "includePath": [ "/usr/include", "/usr/local/include", "${workspaceRoot}" ], "defines": [], "intelliSenseMode": "clang-x64", "browse": { "path": [ "/usr/include", "/usr/local/include", "${workspaceRoot}" ], "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" }, "macFrameworkPath": [ "/System/Library/Frameworks", "/Library/Frameworks" ] }, { "name": "Linux", "includePath": [ "/usr/include", "/usr/local/include", "${workspaceRoot}" ], "defines": [], "intelliSenseMode": "clang-x64", "browse": { "path": [ "/usr/include", "/usr/local/include", "${workspaceRoot}" ], "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" } }, { "name": "Win32", "includePath": [ "C:/MinGW/include", "${workspaceRoot}" ], "defines": [ "_DEBUG", "UNICODE" ], "intelliSenseMode": "msvc-x64", "browse": { "path": [ "C:/MinGW/include", "${workspaceRoot}" ], "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" } } ], "version": 3 }
另外在 tasks.json 中的 "tasks/args" 中加入 "--target=x86_64-w64-mingw"。
9. 設置編譯環境 (安裝了 Code Runner插件 的話,這個設置就不再起作用)
在 VS Code 中點擊 hello.cpp 回到 hello.cpp 文件,調用快捷鍵 Ctrl+Shift+B 構建可執行文件。 此時 VS Code 會報錯,在 VS Code 的頂欄顯示“No task runner configured”,你只需要點擊右邊的藍色按鈕“Configure task runner”來生成編輯 tasks.json 即可。 選擇后會創建並打開一個 tasks.json 的配置文件, 修改其中的 command 和 args 變量並保存:
"command": "g++ "
"args": [ "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}.exe", "--target=x86_64-w64-mingw", "-std=c++17" ]
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "echo", "type": "shell", // "command": "echo Hello", "command": "g++ ", // 如果用MinGW,編譯C用gcc,編譯c++用g++。如果用CLang,編譯"clang++", // // "args": ["-g", "${file}", "-o", "${workspaceRoot}/hello.exe"], "args": [ "-g", // 生成和調試有關的信息 "${file}", "-o", // 指定輸出文件名,不加該參數則默認輸出a.exe "${fileDirname}/${fileBasenameNoExtension}.exe", "-c -fexec-charset=GBK -finput-charset=UTF-8", "-Og", // "-Wall", // 開啟額外警告 // "-static-libgcc", // 靜態鏈接 "-fcolor-diagnostics", "--target=x86_64-w64-mingw", // 默認target為msvc,不加這一條就會找不到頭文件 "-std=c++17" // c++1z即c++17,C++語言最新標准為c17 ], // 編譯命令參數 "group": { "kind": "build", "isDefault": true // 設為false可做到一個tasks.json配置多個編譯指令,需要自己修改本文件 } } ] }
10. 設置編譯等環境
點擊“文件/首選項/設置”菜單,修改 settings.json 配置文件, 在左側的“默認設置”下找到“Run Code configuration”下的 "code-runner.executorMap" ,點擊其左側的“筆”圖標,選擇“在設置中替換”,將內容復制到右側的“用戶設置”中,修改其中的 "c" / "cpp" 項,使其支持 中文 和 C++17 標准。
11. 增加對 C++17 標准的支持
GNU GCC 7.2 直接支持 C++11 / C++14 標准,無需進行任何修改。如果需要支持 C++17 標准的話,則需要修改“用戶設置”中的 "c" / "cpp" 項,加入“-std=c++17”。
"cpp": "cd $dir && g++ -std=c++17 $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt"
{ "code-runner.executorMap": { "javascript": "node", "java": "cd $dir && javac $fileName && java $fileNameWithoutExt", "c": "cd $dir && gcc $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "cpp": "cd $dir && g++ -std=c++17 $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "objective-c": "cd $dir && gcc -framework Cocoa $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "php": "php", "python": "python", "perl": "perl", "perl6": "perl6", "ruby": "ruby", "go": "go run", "lua": "lua", "groovy": "groovy", "powershell": "powershell -ExecutionPolicy ByPass -File", "bat": "cmd /c", "shellscript": "bash", "fsharp": "fsi", "csharp": "scriptcs", "vbscript": "cscript //Nologo", "typescript": "ts-node", "coffeescript": "coffee", "scala": "scala", "swift": "swift", "julia": "julia", "crystal": "crystal", "ocaml": "ocaml", "r": "Rscript", "applescript": "osascript", "clojure": "lein exec", "haxe": "haxe --cwd $dirWithoutTrailingSlash --run $fileNameWithoutExt", "rust": "cd $dir && rustc $fileName && $dir$fileNameWithoutExt", "racket": "racket", "ahk": "autohotkey", "autoit": "autoit3", "dart": "dart", "pascal": "cd $dir && fpc $fileName && $dir$fileNameWithoutExt", "d": "cd $dir && dmd $fileName && $dir$fileNameWithoutExt", "haskell": "runhaskell", "nim": "nim compile --verbosity:0 --hints:off --run" } }
12. 對 中文漢字 的支持
VS Code 默認使用 UTF-8 編輯源程序並編譯成 UTF-8 的程序,因此,在 VS Code 中編輯編譯的程序在 VS Code 中運行不會出現亂碼。
但是,Windows 下的 命令提示符 和 PowerShell 的代碼頁默認為 GBK ,因此在它們窗口下直接運行程序,其中的中文漢字會變成亂碼。解決方法有兩種:
方法一,在窗口下運行以下命令,修改運行窗口的代碼頁
chcp 65001 # 就是換成UTF-8代碼頁,然后再運行程序
chcp 936 # 可以換回默認的GBK,
chcp 437 #是美國英語
方法二,修改程序的編碼
打開源程序窗口,點擊窗口右下角的編碼,例如“UTF-8”,選擇“通過編碼重新打開”下的“Chinese (GBK)”,將編碼變成 GBK ,即可以修改源程序的編碼。
再在11步中的“用戶設置”中的 "c" / "cpp" 項,加入“-fexec-charset=GBK”,編譯后程序為 GBK 編碼,它可以在默認的 命令提示符 窗口運行,但是在 VS Code 里面運行會出現亂碼。
"cpp": "cd $dir && g++ -fexec-charset=GBK -std=c++17 $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt"
13. 設置運行環境
打開 launch.json 的配置文件, 修改其中的 program 和 miDebuggerPath 變量並保存:
"program": "${workspaceFolder}/${fileBasenameNoExtension}.exe"
"miDebuggerPath": "gdb.exe"
{ // 使用 IntelliSense 了解相關屬性。 // 懸停以查看現有屬性的描述。 // 欲了解更多信息,請訪問: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "(gdb) Launch", // 配置名稱,將會在啟動配置的下拉菜單中顯示 "type": "cppdbg", // 配置類型,這里只能為cppdbg "request": "launch", // 請求配置類型,可以為launch(啟動)或attach(附加) "program": "${workspaceFolder}/${fileBasenameNoExtension}.exe", // 將要進行調試的程序的路徑 // "program": "enter program name, for example ${workspaceFolder}/a.exe", // "program": "${fileDirname}/${fileBasenameNoExtension}.exe", // 將要進行調試的程序的路徑 "args": [], // 程序調試時傳遞給程序的命令行參數,一般設為空即可 "stopAtEntry": false, // 設為true時程序將暫停在程序入口處 "cwd": "${workspaceFolder}", // 調試程序時的工作目錄 "environment": [], "externalConsole": true, // 調試時是否顯示控制台窗口,一般設置為true顯示控制台 "MIMode": "gdb", // 指定連接的調試器,可以為gdb或lldb。但目前lldb在windows下沒有預編譯好的版本。 // "miDebuggerPath": "/path/to/gdb", // 調試器路徑。 "miDebuggerPath": "gdb.exe", // 調試器路徑。 "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } // "preLaunchTask": "Compile" // 調試會話開始前執行的任務,一般為編譯程序。與tasks.json的taskName相對應 ] }
14. 點擊右上角的 三角 圖標,運行程序
15.測試代碼
C語言測試代碼:
#include <stdio.h> void swap(int* pa, int* pb) { *pa = *pa ^ *pb; *pb = *pa ^ *pb; *pa = *pa ^ *pb; } int main() { int a = 5, b = 8; printf("交換前:\ta = %d, b = %d\n", a, b); swap(&a, &b); printf("交換后:\ta = %d, b = %d\n", a, b); return 0; }
C++11語言測試代碼:
#include <iostream> #include <iomanip> // std::setw #include <vector> // 一維數組 輸出 楊輝三角形 int main() { using std::cout; using std::endl; using std::setw; using std::vector; constexpr size_t Line = 16; constexpr unsigned W = 5; size_t i, j; int n[Line+1]; cout << "\t\tPascal 三角形\n" << endl; cout << setw(W) << (n[1] = 1) << endl; for (i = 2; i != Line+1; ++i) { cout << setw(W) << (n[i] = 1); for (j = i-1; j != 1; --j) cout << setw(W) << (n[j] += n[j-1]); cout << setw(W) << n[1] << endl; } cout << endl << endl; using std::begin; using std::end; cout << setw(W) << (n[1] = 1) << endl; for (int *pl = begin(n)+2; pl != end(n); ++pl) { cout << setw(W) << (*pl = 1); for (int *pr = pl-1; pr != begin(n)+1; --pr) cout << setw(W) << (*pr += *(pr-1)); cout << setw(W) << n[1] << endl; } cout << endl << endl; int nn[Line] = {0}, t; bool beg = true; for (auto ll : nn) { beg = true; for (auto &mm : nn) if (beg && mm == 1) { cout << setw(W) << (t = mm = 1); beg = false; } else if (mm == 0) { cout << setw(W) << (mm = 1) << endl; break; } else { cout << setw(W) << (mm += t); t = mm-t; } } cout << endl << endl; vector<unsigned> v(Line, 0); cout << setw(W) << (v[0] = 1) << endl; for (i = 1; i != Line; ++i) { cout << setw(W) << (v[i] = 1); for (j = i-1; j != 0; --j) cout << setw(W) << (v[j] += v[j-1]); cout << setw(W) << v[0] << endl; } cout << endl << endl; for (auto &ll : v) { ll = 0; beg = true; for (auto &mm : v) if (beg && mm == 1) { cout << setw(W) << (t = mm = 1); beg = false; } else if (mm == 0) { cout << setw(W) << (mm = 1) << endl; break; } else { cout << setw(W) << (mm += t); t = mm-t; } } cout << endl << endl; cout << setw(W) << (v[0] = 1) << endl; for (vector<unsigned>::iterator it = v.begin()+1; it != v.end(); ++it) { cout << setw(W) << (*it = 1); for (vector<unsigned>::reverse_iterator rit(it); rit != v.rend()-1; ++rit) cout << setw(W) << (*rit += *(rit+1)); cout << setw(W) << *(v.cbegin()) << endl; } cout << endl << endl; return 0; }
C++11語言shared_ptr測試代碼:
#include <iostream> #include <memory> // for std::shared_ptr class Resource { public: Resource() { std::cout << "Resource acquired\n"; } ~Resource() { std::cout << "Resource destroyed\n"; } }; int main() { // allocate a Resource object and have it owned by std::shared_ptr Resource *res = new Resource; std::shared_ptr<Resource> ptr1(res); { std::shared_ptr<Resource> ptr2(ptr1); // use copy initialization to make another std::shared_ptr pointing to the same thing // std::shared_ptr<Resource> ptr2(res); // create ptr2 directly from res (instead of ptr1) std::cout << "Killing one shared pointer\n"; } // ptr2 goes out of scope here, but nothing happens std::cout << "Killing another shared pointer\n"; return 0; } // ptr1 goes out of scope here, and the allocated Resource is destroyed
C++17語言測試代碼:
// 引用自: http://www.bfilipek.com/2017/09/cpp17-details-utils.html #include <string> #include <iostream> #include <any> #include <map> int main() { auto a = std::any(12); // set any value: a = std::string("你好!"); a = 16; // reading a value: // we can read it as int std::cout << std::any_cast<int>(a) << '\n'; // but not as string: try { std::cout << std::any_cast<std::string>(a) << '\n'; } catch(const std::bad_any_cast& e) { std::cout << e.what() << '\n'; } // reset and check if it contains any value: a.reset(); if (!a.has_value()) { std::cout << "a 是空的!" << "\n"; } // you can use it in a container: std::map<std::string, std::any> m; m["integer"] = 10; m["string"] = std::string("你好,親"); m["float"] = 1.0f; for (auto &[key, val] : m) { if (val.type() == typeid(int)) std::cout << "int: " << std::any_cast<int>(val) << "\n"; else if (val.type() == typeid(std::string)) std::cout << "string: " << std::any_cast<std::string>(val) << "\n"; else if (val.type() == typeid(float)) std::cout << "float: " << std::any_cast<float>(val) << "\n"; } }
參考文獻:
https://code.visualstudio.com/docs/languages/cpp
https://blogs.msdn.microsoft.com/c/2016/04/18/visual-studio-code的cc擴展功能/