大家知道計算機使用的一系列的1和0
那個一個C++語言程序又是如何從一個個.h和.cpp文件變成包含1和0的可執行文件呢?
可以認為有以下的幾個環節
源程序->預處理->編譯和優化->生成目標文件->鏈接->可執行文件
1.預處理
C++的預處理是指在C++程序源代碼被編譯之前,由預處理器對C++程序源代碼進行的處理。這個過程並不對程序的源代碼進行解析。
這里的預處理器(preprocessor)是指真正的編譯開始之前由編譯器調用的一個獨立程序。
預處理器主要負責以下的幾處
1.宏的替換
2.刪除注釋
3.處理預處理指令,如#include,#ifdef
如我們有以下代碼
temp.h
#ifndef _HEADERNAME_H #define _HEADERNAME_H 1 #include <iostream> inline void show(char *a) { std::cout << a<< std::endl;//annotation } #endif
main.cpp
#include "temp.h" #define MACRO "This is a macro" extern int i; int main() { std::cout<<i<<std::endl; show(MACRO); }
a.cpp
#include <iostream> int i=100;
*在vs2013中可以使用“VS2013 開發人員命令提示”
使用cl /P main.cpp只進行預編譯生成main.i文件
*g++中可以使用(在以下只使用g++進行演示)
g++ –E main.cpp>main.i命令
g++ –E a.cpp>main.i
打開生成的A.i文件
我們發現
1、show函數中的注釋已經被刪掉了
2、main函數中的MACRO宏被替成了"this is a macro”
windows vs下
3、temp.h和main.cpp中的#include<iostream> 和#include “temp.h”也在相應位置被展開了
2.編譯和優化
詞法分析 -- 識別單詞,確認詞類;比如int i;知道int是一個類型,i是一個關鍵字以及判斷i的名字是否合法
語法分析 -- 識別短語和句型的語法屬性;
語義分析 -- 確認單詞、短語和句型的語義特征;
代碼優化 -- 修辭、文本編輯;
代碼生成 -- 生成譯文。
內聯函數的替換就發生在這一階段
在g++中可以使用
g++ -S將預處理階段生成的.i文件生成相應的匯編文件
g++ –S main.i main.s
g++ –S a.i a.s
生成的部分代碼如下:
3.生成目標文件
匯編過程實際上指把匯編語言代碼翻譯成目標機器指令的過程。
在最終的目標文件中
除了擁有自己的數據和二進制代碼之外,還要至少提供2個表:未解決符號表和導出符號表,分別告訴鏈接器自己需要什么和能夠提供什么。
編譯器把一個cpp編譯為目標文件的時候,除了要在目標文件里寫入cpp里包含的數據和代碼,還要至少提供3個表:未解決符號表,導出符號表和地址重定向表。
未解決符號表提供了所有在該編譯單元里引用但是定義並不在本編譯單元里的符號及其出現的地址。
導出符號表提供了本編譯單元具有定義,並且願意提供給其他編譯單元使用的符號及其地址。
地址重定向表提供了本編譯單元所有對自身地址的引用的記錄。
g++中可以使用g++ -c命令
g++ –c main.s –o main.o
g++ –c a.s –o a.o
4.鏈接
由匯編程序生成的目標文件並不能立即就被執行,其中可能還有許多沒有解決的問題。例如,某個源文件中的函數可能引用了另一個源文件中定義的某個符號(如變量或者函數調用等);在程序中可能調用了某個庫文件中的函數,等等。所有的這些問題,都需要經鏈接程序的處理方能得以解決。
g++ a.o main.o –o main.out
最終運行結果如下
100
This is a macro
參考文獻
C/C++程序從編譯到最終生成可執行文件的過程分析 http://blog.csdn.net/wyb19890515/article/details/7211006
c/c++程序編譯連接過程 http://blog.csdn.net/hitprince/article/details/7880241






