對於.c后綴的文件,gcc把它當做是C程序,g++當做是C++程序;對於.cpp后綴的文件,gcc和g++都會當做c++程序。gcc可以根據后綴名為.c或.cpp分別按c程序和c++程序來編譯,但是g++無論是.c或.cpp都統一按c++程序來編譯。
編譯階段,g++會調用gcc,鏈接階段通常會用g++來完成,g++在編譯的過程中,其實是調用gcc按照c++程序來編譯的。即編譯工作最終都是由gcc來完成的。這是因為gcc命令不能自動和c++程序使用的庫連接。而g++則會自動調用鏈接的c++庫。
gcc可以用來編譯c++但是它不會自動調用鏈接的c++庫,你需要自己手動鏈接,使用如下命令:
gcc main.cpp -lstdc++
注:main.cpp -lstdc++ 位置不能換,換了位置筆者編譯出現了 main.cpp:(.text+0x2d):undefined reference to`std::cout' 等一系列的錯誤
gcc/g++在執行編譯工作的時候,分為以下四個過程:
1.預處理,生成.i的文件
2.將預處理后的文件轉換成匯編語言,生成.s文件
3.匯編變為目標代碼(機器代碼)生成.o的文件
4.連接目標代碼,生成可執行程序
下面用個小例子說明這四個過程:
//This is the test code #include <iostream>
using namespace std;
#define pi 3.14
static int t = 1;
int main() { cout<<"Hello World: The t+pi is "<<t+pi<<endl; return 0; }
(1)預處理階段
g++ -E main.cpp > main.i
預處理后的文件 linux下以.i為后綴名,這個過程只激活預處理,不生成文件,因此你需要把它重定向到一個輸出文件里 。
這一步的功能:
宏的替換,還有注釋的消除,還有找到相關的庫文件,將#include文件的全部內容插入。若用<>括起文件則在系統的INCLUDE目錄中尋找文件,若用" "括起文件則在當前目錄中尋找文件。
用編輯器打開main.i會發現有很多很多代碼,你只需要看最后部分就會發現,預處理做了宏的替換,還有注釋的消除,可以理解為無關代碼的清除。
cat main.i
下面是main.i文件的最后部分,可以看見宏的替換和注釋的消除。

(2)將預處理后的文件轉換成匯編語言,生成.s文件
g++ -S main.cpp
這一步的功能:
生成main.s文件,.s文件表示是匯編文件,用編輯器打開就都是匯編指令。cat main.s
下面是main.s文件的一部分:

(3)匯編變為目標代碼(機器代碼)生成.o的文件
g++ -c main.cpp
這一步的功能:
cat main.o
下面是main.o文件的一部分:

(4)連接目標代碼,生成可執行程序
g++ main.o -o main //生成的可執行程序名為main ,如果執行命令 g++ main.o 這樣默認生成a.out,也就是main與a.out是一個只是名字不同而已
下面是main文件的一部分:

ls

./main


在成功編譯之后,就進入了鏈接階段。在這里涉及到一個重要的概念:函數庫(可以這么理解就是不帶main()函數的.cpp生成的)。
讀者可以重新查看這個小程序,在這個程序中並沒有定義”cout”的函數(准確說cout不是函數,cout卻很獨特:既不是函數,似乎也不是C++特別規定出來的像if,for一類有特殊語法的“語句”,其實說到底還是函數調用,不過這函數有些特殊,用的是運算符重載,確切地說是重載了“<<”運算符。這里如果用pritf()函數說明會更好,暫且當做函數理解吧)實現,且在預編譯中包含進的”iostream”中也只有該函數的聲明,而沒有定義函數的實現,那么,是在哪里實現”cout”函數的呢?系統把這些函數實現都被做到名為stdc++的庫文件中去了,在沒有特別指定時,g++會到系統默認的搜索路徑”/usr/lib”下進行查找,也就是鏈接到stdc++庫函數中去,這樣就能實現函數”cout”了,而這也就是鏈接的作用。
函數庫一般分為靜態庫和動態庫兩種。
下一篇將具體介紹。