前言:作者接觸的第一門編程語言是Python。作為一門典型的動態語言,Python的一個小小安裝器為我們解決了很多環境配置上潛在的麻煩,一個自帶的IDLE (Integrated Development and Learning Environment)也足夠簡單而完整,為快速入門上手掃除了很多障礙。更多擴展性的應用,也在官方的文檔中闡述得相當詳盡。
但C語言看起來完全不同。作為一門老牌的靜態語言,以編譯器為核心的編程環境的配置,以及編譯、鏈接、生成等諸多步驟,相較拿一個.py文件就能跑的Python,對缺少有關經驗的新手來說,確是有點頭疼。作者經過諸多探索,最終決定的上手方案是Visual Studio,下面詳細介紹。
Visual Studio是微軟(Microsoft)為以Windows為主的平台開發的一套功能全面而強大的IDE(集成開發環境),支持C#、F#、VB、C/C++等多種語言的開發。
作者個人推薦使用Visual Studio 2017的最新版本(目前版本號為15.9.34)。除非還有使用C#和VB兩門語言的需求,或者電腦系統是2015年以前的版本,否則不推薦VS 2015以前的版本(因為會強制附帶C#和VB的組件,且安裝時會設置系統還原點速度極慢,裝好的占用還要多出幾GB;另外,2015以前的版本對C/C++語言標准的支持非常不完善,非常不現代)。最新的VS 2019版也不錯,但新建項目的頁面相較前代做了大改,容易勸退部分依賴老教程的萌新。
Visual Studio的安裝
VS的官方網站為
在這里你可以看到它的簡介。
不管是2015、2017還是2019,VS都有三個主要版本可供選擇:Community是免費的社區版,Professional和Enterprise是收費的專業版和企業版,對於初學者三者沒有區別。如果不是專業版或企業版密鑰的持有者,請放心下載社區版。
VS的下載頁面為

在這個頁面上只有最新版本(目前是VS 2019)可供下載。如果想下載舊版本(如2017、2015等),請訪問
不過現在下載舊版本需要微軟賬號並注冊Dev Essentials計划,而且考慮到微軟這類冷門服務連接起來着實費勁,故我這里放一個VS 2017的直接下載鏈接(右鍵復制到瀏覽器地址欄或下載器中即可)
不確定這個鏈接是否永久有效,失效可私信我或自行注冊Dev Essentials
下載下來的是一個名為vs_community.exe的小小安裝器 (1.2MB)。雙擊啟動之后,會進行Visual Studio Installer的安裝 (幾十MB)。它是VS 2017及以后特有的東西,是VS本體的安裝管理器,裝好並啟動之后,選擇Community社區版,你應該會進入一個類似這樣的界面。

在上面的【工作負載】選項卡,你需要按照你的開發目標選擇你需要的VS組件。實現C/C++編程必須配置的工作負載為“使用C++的桌面開發”。這套組件已包含生成“桌面應用”——即Windows上傳統的的.exe程序——必備的所有環境。注意雖然它名字中只提到了C++,但對純C同樣是支持的,編寫時注意規范即可(下文會講)。
另一種與此對應的“通用Windows平台 (Universal Windows Platform) 開發”,目標則是新型的UWP應用程序,這是指能夠上架Microsoft Store的那種軟件,並不是初學者需要的,如果誤勾選會浪費10GB+的硬盤空間。
VS 2017 除了支持 C/C++ 開發,還支持 C#、F#、Visual Basic 等開發語言,我們沒有必要安裝所有的組件,只需要安裝 “使用C++ 的桌面開發” 即可。
同時在這個頁面,還可以選擇 VS 2017 的存儲位置,也可選擇其他盤。然后直接點擊安裝,安裝過程可能需要一段時間,大家耐心等待。
在【語言包】選項卡可選擇額外的安裝語言

在【安裝位置】選項卡可以選擇軟件本體、下載緩存、共享組件的安裝位置。注意,你可以選擇非默認的位置,但必須確保第一和第三個路徑中不包含任何中文,否則很可能出現裝好不能用的情況!切記切記!!

【單個組件】的配置通常無需理會。保持網絡暢通,確認后,等待自動下載安裝完畢即可。
安裝好后的界面如下圖所示

本編程環境大約5GB。基於VS Code或Sublime等搭配MinGW等編譯器套件可以配置更為精簡的環境,有興趣可參見
Visual Studio中的“項目”和“解決方案”
跟一些簡單的編程環境不同,VS以一個項目作為我們編寫程序的基本組織單元。它包含生成一個目標程序所需的所有源代碼和各種資源等,也會存儲該項目編寫和生成過程中的諸多中間信息和日志。而解決方案,則又是項目的容器,它允許我們將多個相關或有依賴的項目組織在一起,方便高效處理。
編程以任務為導向。下面以一個最簡單的HelloWorld程序和稍復雜的連加器程序,分別展示單項目和多項目的解決方案中C語言的使用。
HelloWorld程序(單項目)
在菜單欄,選擇【文件】→【新建】→【項目】(快捷鍵Ctrl+Shift+N),

在彈出的【新建項目】對話框中,左側有已安裝可供你選擇的項目類型,我們展開【Visual C++】這一欄。要編寫純C程序,建議選擇【其他】→【空項目】(避免混入不需要的C++依賴)。
如果確是要編寫C++程序,【Windows桌面】→【控制台應用】也是可以的

在下面設定好你的項目名稱以及位置,確保右下方“為解決方案創建目錄”已勾選,點擊確定。
項目新建成功后,一般界面右側為“解決方案資源管理器”(如果找不到,點擊【視圖】→【解決方案資源管理器】將其喚出,快捷鍵Ctrl+Alt+L),在其中你可以看到我們創建的Project1項目被自動置入到了一個同名的解決方案中。


右鍵項目名稱下的【源文件】,選擇【添加】→【新建項】(快捷鍵Ctrl+Shift+A),

在彈出的【添加新項】對話框中,選擇【Visual C++】一欄中的【代碼】,你將看到C++項目支持的各種類型的代碼文件。常用的C++代碼格式是第一個,后綴名為.cpp,這里並沒有列出純C要用的.c格式。

我們需要在底下手動修改文件后綴名,比如把文件名稱改為src1.c(啥名字都行,但注意一定要連着后綴名一塊改,VS的編譯器可以辨認這是純C代碼),然后確認。

你將看到【源文件】下被添加了一個“C”文件,雙擊它在主界面打開該文件,你就可以輸入你的C代碼了。

要生成該項目的目標程序(也就是Window上最常見的.exe程序),一般是選擇菜單欄中的【生成】→【生成解決方案】

生成過程中,你將在下面“輸出”面板中看到一些信息。如果你的程序包含錯誤,這里則會輸出不一樣的信息,詳情可點擊左側“錯誤列表”查看。

通常倒數第二行->
后面的一串字符就是生成的目標程序路徑,在本機上,可以直接將該路徑復制到命令行運行,即


當然,在VS這樣強大的IDE里顯然不需要這樣復制粘貼來執行程序(但新手應該知道這種沒有圖形界面的程序本質上是如何運行的!),我們只需選擇菜單欄中的【調試】→【開始執行(不調試)】(快捷鍵Ctrl+F5)。


IDE將自動啟動一個控制台並執行由該項目生成的程序。

注意,如果你尚未生成目標程序而直接選擇執行,VS將自動替你完成生成的步驟,也就是說前面生成解決方案的步驟是可以省略的。但作為教程這里還是加以介紹,希望讀者明白其中包含的基本過程。
如果你非要使用F5或者實心的運行按鈕,在程序中沒有斷點的情況下,程序可能會在結束后自動關閉而給人一閃而過的效果。你需要找到下圖所示位置禁用自動關閉。

某些情況下即使使用了Ctrl+F5正常執行,也可能遇到一閃而過的情況(VS 2017最新版不會有這種情況,建議升級),這時需要一個額外的設置。在“解決方案資源管理器”中,選擇我們的項目(注意是那個帶兩個加號的項目圖標,不是解決方案的圖標),然后右鍵,選擇【屬性】,

在屬性頁左側展開【鏈接器】,選擇【系統】,將右側【子系統】項的值修改為“控制台”。確定退出。

簡易連加器程序(多項目)
還是像上一節一樣創建一個項目。

但不同的是,這次我們還額外往解決方案中添加了其他幾個項目。它們並沒有相互依賴,只是都是我同一學習章節的內容,組織在一起比較方便。VS默認將多項目解決方案中第一個添加的作為啟動項目,每次執行會固定從它開始啟動。這就給我們分別調試不同的項目帶來了不便,解決的方法為
右鍵解決方案的圖標,選擇【屬性】,

在解決方案的屬性頁中,選擇左側【通用屬性】→【啟動項目】,再選擇“當前選定內容”作為啟動項目。

確定回到代碼頁,在我們當前RudiCalc項目下,快捷鍵Ctrl+F5執行,此時其他無關項目被自動忽略,結果如下

這個程序會自動讀取當前行並轉化為數字,然后與已有的數值累加起來輸出,感興趣的可以拿走源代碼回去試試。
#include <stdio.h> #include <ctype.h> #define MAXLINE 100 /* rudimentary calculator */ main() { double sum, atof(char[]); char line[MAXLINE]; int getline(char line[], int max); sum = 0; while (getline(line, MAXLINE) > 0) printf("\t%g\n", sum += atof(line)); return 0; } /* atof: convert string s to double */ double atof(char s[]) { double val, power; int i, sign; for (i = 0; isspace(s[i]); i++) ; sign = (s[i] == '-') ? -1 : 1; if (s[i] == '+' || s[i] == '-') i++; for (val = 0.0; isdigit(s[i]); i++) val = 10.0 * val + (s[i] - '0'); if (s[i] == '.') i++; for (power = 1.0; isdigit(s[i]); i++) { val = 10.0 * val + (s[i] - '0'); power *= 10.0; } return sign * val / power; } /* getline: get line into s, return length */ int getline(char s[], int lim) { int c, i; i = 0; while (--lim > 0