c程序編譯流程
程序的基本流程如圖:
1. 預處理
預處理相當於根據預處理指令組裝新的C/C++程序。經過預處理,會產生一個沒有宏定義,沒有條件編譯指令,沒有特殊符號的輸出文件,這個文件的含義同原本的文件無異,只是內容上有所不同。
-
讀取C/C++源程序,對其中的偽指令(以#開頭的指令)進行處理
①將所有的“#define”刪除,並且展開所有的宏定義
②處理所有的條件編譯指令,如:“#if”、“#ifdef”、“#elif”、“#else”、“endif”等。這些偽指令的引入使得程序員可以通過定義不同的宏來決定編譯程序對哪些代碼進行處理。預編譯程序將根據有關的文件,將那些不必要的代碼過濾掉。
③處理“#include”預編譯指令,將被包含的文件插入到該預編譯指令的位置。
(注意:這個過程可能是遞歸進行的,也就是說被包含的文件可能還包含其他文件)
-
刪除所有的注釋
-
添加行號和文件名標識。
以便於編譯時編譯器產生調試用的行號信息及用於編譯時產生的編譯錯誤或警告時能夠顯示行號
-
保留所有的#pragma編譯器指令
2. 編譯
將預處理完的文件進行一系列詞法分析、語法分析、語義分析及優化后,產生相應的匯編代碼文件。
3. 匯編
將編譯完的匯編代碼文件翻譯成機器指令,並生成可重定位目標程序的.o文件,該文件為二進制文件,字節編碼是機器指令。
匯編器是將匯編代碼轉變成機器可以執行的指令,每一個匯編語句幾乎都對應一條機器指令。所以匯編器的匯編過程相對於編譯器來講比較簡單,它沒有復雜的語法,也沒有語義,也不需要做指令優化,只是根據匯編指令和機器指令的對照表一一翻譯即可。
4. 鏈接
通過鏈接器將一個個目標文件(或許還會有庫文件)鏈接在一起生成一個完整的可執行程序。
由匯編程序生成的目標文件並不能立即就被執行,其中可能還有許多沒有解決的問題。
例如,某個源文件中的函數可能引用了另一個源文件中定義的某個符號(如變量或者函數調用等);在程序中可能調用了某個庫文件中的函數,等等。所有的這些問題,都需要經鏈接程序的處理方能得以解決。
鏈接程序的主要工作就是將有關的目標文件彼此相連接,也就是將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標文件成為一個能夠被操作系統裝入執行的統一整體。
命令行下編譯文件
因為VS自帶了開發人員選項,所以我們不需要再去配置環境變量了(感謝微軟~)。
- 在win10中詢問Cortana,輸入VS,選擇VS2015開發人員命令提示。
- 進入.c或者.cpp文件所在路徑,輸入命令:cl *.cpp,編譯預先用記事本或者Editplus寫好的文件,查看結果
- 如上圖所示,生成了兩個文件,一個輸出文件:hello.exe,一個obj文件:hello.obj;查看文件夾:
- 執行.exe文件,查看運行結果,如下圖:
說明
在以上的編譯過程中我們只用了cl的編譯命令就幫我們最終的可執行文件HelloWorld.exe,這是因為cl.exe程序在編譯時自己會去調用link.exe、lib.exe等程序。
可通過”cl -help “查看常用的編譯選項
選項 | 作用 |
---|---|
/O1 | 創建小代碼 |
/O2 | 創建快速代碼 |
/Oa | 假設沒有別名 |
/Ob | 控制內聯展開 |
/Od | 禁用優化 |
/Og | 使用全局優化 |
/Oi | 生成內部函數 |
更詳細的中文介紹也可參考這篇博文:
http://www.lellansin.com/%E5%BE%AE%E8%BD%AF-cl-exe-%E7%BC%96%E8%AF%91%E5%99%A8.html
靜態庫
打開VS2015,新建一個項目,選擇win32項目,點擊確定,選擇靜態庫這個選項,預編譯頭文件不選。
在這個空項目中,添加一個.h文件和4個.cpp文件。名字我們起為head.h和add.cpp,div.cpp,mul.cpp,sub.cpp
head.h文件:

#include"head.h"
int add(int a, int b)
{
return a + b;
}
#include"head.h"
double div(int a, int b)
{
return (a + 0.0) / (b + 0.0);
}
#include"head.h"
int mul(int a,int b)
{
return a*b;
}
sub.cpp:
#include"head.h"
int sub(int a, int b)
{
return a - b;
}
編譯這個項目之后(生成——》生成解決方案),會在debug文件夾下生成mymath.lib文件,這個就是我們需要的靜態鏈接庫。
下面說明如何調用靜態鏈接庫。
- 首先需要新建一個空項目,起名為test_mymath。
- 將之前static項目下的head.h這個文件復制到mymath項目的目錄下
- 在工程中加入head.h文件,快捷鍵:Ctrl + Alt +A添加現有項:
新建一個20145211hzy.cpp文件如下:

編譯運行可得結果:
#pragma comment(lib,"mymath.lib"),這一句是顯式的導入靜態鏈接庫。除此之外,還有其他的方法,比如通過設置路徑等等,這里不做介紹。
或者 選中工程名,點擊右鍵 -> 屬性, 在“ VC++目錄 ”的包含目錄里面加入head.h的所在目錄的路徑,庫目錄里面加入mymath.lib所在目錄的路徑;在鏈接器->輸入->附加依賴項輸入“mymath.lib”。然后源文件里添加#include"head.h"就OK了。
動態庫
- 創建DLL

#ifdef DLL_API
#else
#define DLL_API _declspec(dllimport)
#endif
DLL_API int add(int a, int b);
#include "dll.h"
#define DLL_API _declspec(dllexport)
int add(int a, int b)
{
return a + b;
}
double div(int a, int b)
{
return (a + 0.0) / (b + 0.0);
}
int mul(int a,int b)
{
return a*b;
}
int sub(int a, int b)
{
return a - b;
}
6.編譯
- 調用DLL
1.在該解決方案中新建一個win32控制台項目;
2.在新項目上單擊右鍵,設為啟動項;
3.再次在新項目上單擊右鍵->添加->引用->項目->解決方案,將DLL項目前邊的方框選中。
4.添加代碼:
#include "stdafx.h"
_declspec(dllexport) int add(int a, int b);
_declspec(dllexport) int sub(int a, int b);
_declspec(dllexport) int MUL(int a, int b);
_declspec(dllexport) double div(int a, int b);
int main()
{
int a=3, b=4;
printf("%d\n", add(a,b));
printf("%d\n", sub(a,b));
printf("%lf\n", divs(a, b));
printf("%d\n", mul(a, b));
system("pause");
return 0;
}
5.編譯完成。
- 其他
如果創建與調用不在同一個解決方案內,需要將生成的mymath.lib文件復制到win32項目文件夾中,並添加引用命令:
#pragma comment(lib,"mymath.lib"),或者在項目->屬性->VC++目錄中手動添加;
再將mymath.dll文件放入win32項目的調試文件夾中。
關於調試
調試是VS2015很強大的一項功能,它可以幫我們找到程序中的很多錯誤。
開始調試
先貼出我的測試代碼(需要說明的是,這段代碼並沒有問題):
#include <stdio.h>
#include"windows.h"
int sum(int m);
int main()
{
int * pi;
int i, n = 0;
pi = &i;
int arr[3] = { 10, 20, 30 };
pi = arr;
sum(50);
for (i = 0; i <= 50; i++)
{
n += i;
}
printf("The sum of 1-50 is %d \n", n);
system("pause");
}
int sum(int m)
{
int i, n = 0;
for (i = 1; i <= m; i++)
{
n += i;
}
printf("The sum of 1-50 is %d \n", n);
return n;
}
1. 設置斷點:可以直接在你需要設置斷點的地方按F9,或者在那行右鍵->斷點->插入斷點(下面會介紹如何設置函數、臨時、條件斷點);雙擊紅點,撤銷斷點。
2. 調試:逐過程調試:按F10,或者點擊菜單欄的調試–>逐過程;
逐語句調試:按F11,或者點擊菜單欄的調試–>逐語句
函數斷點:
- 在main處設置斷點,逐過程調試,因為在main處設置了斷點,main函數還未執行
- 繼續按F10,直到運行完畢
兩個斷點間的調試(關於函數斷點的逐過程和逐語句):
在調試過程中F5是執行到下一個斷點。F10是逐過程,與逐語句不同的是,在執行到下圖中斷點時,再執行會執行斷點下面的語句,而不是去執行語句中的方法。
而F11是逐語句,在執行到下圖中的斷點 時,按F11會執行到sum里面逐步記錄執行過程。
條件斷點:
設置條件斷點非常容易。在特定的行上,按F9設置斷點;然后右擊斷點–編輯窗口左側的紅點,在上下文菜單上選擇“條件”。
現在我再運行這個程序按F5達到條件斷點,只有當x等於5時,程序運行才會被中斷。對於其它條件下的x值,斷點將被跳過。
3. 完畢:
Alt+F4強行退出調試:
3. 相關快捷鍵總結:
F6: 生成解決方案
Ctrl+F6: 生成當前項目
F7: 查看代碼
Shift+F7: 查看窗體設計器
F5: 啟動調試
Ctrl+F5: 開始執行(不調試)
Alt+F4: 停止調試
Ctrl+Shift+F5: 重啟調試
F9: 切換斷點
Ctrl+F9: 啟用/停止斷點
Ctrl+Shift+F9: 刪除全部斷點
F10: 逐過程
Ctrl+F10: 運行到光標處
F11: 逐語句
總結
VS2015是一個非常好的軟件,我今天分享的知識冰山一角,可以做的還有很多!