在Linux環境下,我們通常用gcc將C代碼編譯成可執行文件,如下就是一個簡單的例子:
代碼文件:hello.c
#include <stdlib.h>
#include <stdio.h>
void main(void)
{
printf("hello world!\r\n");
}
可以通過如下指令來編譯出一個可執行文件:
gcc hello.c
執行完該命令后,就會得到一個a.out的可執行文件。
編譯的過程
前面的例子只是簡單的介紹了一下gcc的使用方法,熟悉c編程的朋友就會知道,該步驟其實包含了預處理-->編譯-->匯編-->鏈接四步,這四步分別實現的功能如下:
-
預處理階段:主要處理源文件中的#ifdef、 #include和#define命令,展開宏、讀取定義的符號等。
-
編譯階段:檢查代碼的規范性,把代碼翻譯成匯編語言
-
匯編階段:是把編譯階段生成的".s"文件轉成二進制目標代碼
-
鏈接階段:將匯編階段生成的機器碼匯集成一個可執行的二進制代碼文件
由此可以看出,每一個階段的輸出其實就是下一個階段的輸入,用gcc是可以單獨執行這四步的:
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
gcc -c hello.s -o hello.o
gcc hello.o -o hello.exe
實際上,由於這四個步驟太過於復雜,往往可以像我上面那樣全部集中到一個命令中來執行:
gcc hello.c -o hello.exe
這里我加了一個-o參數來指定輸出名稱,而不是默認的a.out。
如果有多個文件,則可以通過如下方式全部集中起來。
gcc -o test first.c second.c third.c
這個全生成的方式雖然非常簡單,但是存在的一個問題就是:當項目較大時,如果只改了一個文件,仍需要重新編譯索引文件。
為了解決這個問題,我們往往把這個編譯過程拆分成兩步:
-
將各個.c文件分別編譯成.o文件
-
將所有.o文件鏈接成執行文件
gcc –c first.c
gcc –c second.c
gcc –c third.c
gcc -o test first.o second.o third.o
這樣,當third.c文件發生改變時,只需要重新編譯third.c和鏈接即可,這樣就省去了未變化文件的編譯時間,也就是我們通常所說的增量編譯。
gcc –c third.c
gcc -o test first.o second.o third.o
從上面的使用方法中我們也可以看到:
-
當使用-c參數時,若輸入文件時.c則會同時執行執行了預處理、編譯、匯編三個階段,直接生成.o文件。
-
輸入文件為.o時,可以直接執行鏈接操作
由於程序員往往並不關心前面兩個幾個階段生成的輸出文件,通常我們也把預處理、編譯、匯編三個階段合並在一起,統稱為編譯,輸入.c,生成.o。
常用參數:
前面其實已經演示過-E、–S、–c、–o等幾個參數的用法,其中-E及-S很少會用到,-c用於編譯生成.o文件,-o用於指定輸出文件名稱。除了這幾個生成控制的參數外,還有許多參數設置,這里主要介紹一下幾個常用的:
包含頭文件和庫:
-
-Idir: 指定編譯查找頭文件的目錄,常用於查找第三方的庫的頭文件,例:gcc test.c –I../inc -o test。
-
-Ldir : 指定鏈接時查找lib的目錄,常用於查找第三方庫。
-
-llibrary : 指定額外鏈接的lib庫
宏定義:
-
-DMACRO 以字符串"1"(默認值)定義 MACRO 宏。
-
-DMACRO=DEFN 以字符串"DEFN"定義MACRO 宏,注意中間不能有空格。
-
-UMACRO 取消對 MACRO 宏的定義。
調試和可執行文件形式:
-
-g 指示編譯器,在編譯的時產生調試信息。
-
-ggdb 盡可能的生成gdb的可以使用的調試信息(比-g生成的信息更多些)。
-
-static 禁止使用動態庫,編譯得到的程序會比較大,但可以自由運行。
-
-share 盡量使用動態庫,所以生成文件比較小,但是需要系統由動態庫。
告警選項:
-
-Wall 產生盡可能多的警告信息,建議始終帶上
-
-Werror 將所有的警告當成錯誤進行處理
gcc和g++
除了gcc編譯器外,還有另外一個編譯器g++,很多人往往搞不清楚這兩個編譯器的區別,很多人望文生義的認為gcc只能編c代碼,g++只能編c++代碼。實際上這兩個編譯器的主要區別如下:
-
后綴為.c的,gcc把它當作是C程序,而g++當作是c++程序來編譯
-
鏈接的時候gcc不會默認加上-lstdc++選項(g++會),而我們往往又沒有手動加這個選項的習慣,則導致gcc編c++代碼時,用到了stl庫時會出現鏈接失敗。
關於它們的區別的更多信息,可以參考這個文章:http://ldzyz007.iteye.com/blog/865080
為了使用簡單,可以制定如下規則:對c項目使用gcc,對c++項目使用g++。估計當時設計這個名字的意圖也是如此吧。