天天看點

GCC使用入門

一、GCC簡介

通 常所說的GCC是GUN Compiler

Collection的簡稱,除了編譯程式之外,它還含其他相關工具,是以它能把易于人類使用的進階語言編寫的源代碼建構成計算機能夠直接執行的二進制代

碼。GCC是Linux平台下最常用的編譯程式,它是Linux平台編譯器的事實标準。同時,在Linux平台下的嵌入式開發領域,GCC也是用得最普遍

的一種編譯器。GCC之是以被廣泛采用,是因為它能支援各種不同的目标體系結構。例如,它既支援基于宿主的開發(簡單講就是要為某平台編譯程式,就在該平

台上編譯),也支援交叉編譯(即在A平台上編譯的程式是供平台B使用的)。目前,GCC支援的體系結構有四十餘種,常見的有X86系列、Arm、

PowerPC等。同時,GCC還能運作在不同的作業系統上,如Linux、Solaris、Windows等。

除了上面講的之外,GCC除了支援C語言外,還支援多種其他語言,例如C++、Ada、Java、Objective-C、FORTRAN、Pascal等。

本系列文章中,我們不僅介紹GCC的基本功能,還涉及到一些諸如優化之類的進階功能。另外,我們還考察GCC的一些映像操作工具,如size和objcopy等,這将在後續的文章中加以介紹。

二、程式的編譯過程

對于GUN編譯器來說,程式的編譯要經曆預處理、編譯、彙編、連接配接四個階段。從功能上分,預處理、編譯、彙編是三個不同的階段,但GCC的實際操作上,它可以把這三個步驟合并為一個步驟來執行。下面我們以C語言為例來談一下不同階段的輸入和輸出情況。

預處理階段,輸入的是C語言的源檔案,通常為*.c。它們通常帶有.h之類頭檔案的包含檔案。這個階段主要處理源檔案中的#ifdef、

#include和#define指令。該階段會生成一個中間檔案*.i,但實際工作中通常不用專門生成這種檔案,因為基本上用不到;若非要生成這種檔案

不可,可以利用下面的示例指令:

gcc -E test.c -o test.i

在編譯階段,輸入的是中間檔案*.i,編譯後生成彙編語言檔案*.s

。這個階段對應的GCC指令如下所示:

GCC -S test.i -o test.s

在彙編階段,将輸入的彙編檔案*.s轉換成機器語言*.o。這個階段對應的GCC指令如下所示:

GCC -c test.s -o test.o

最後,在連接配接階段将輸入的機器代碼檔案*.s(與其它的機器代碼檔案和庫檔案)彙內建一個可執行的二進制代碼檔案。這一步驟,可以利用下面的示例指令完成:

GCC test.o -o test

上面介紹了GCC編譯過程的四個階段以及相應的指令。下面我們進一步介紹常用的GCC的模式。

三、GCC常用模式

這裡介紹GCC追常用的兩種模式:編譯模式和編譯連接配接模式。下面以一個例子來說明各種模式的使用方法。為簡單起見,假設我們全部的源代碼都在一個檔案test.c中,要想把這個源檔案直接編譯成可執行程式,可以使用以下指令:

$ GCC -o test

這裡test.c是源檔案,生成的可執行代碼存放在一個名為test

的檔案中(該檔案是機器代碼并且可執行)。-o

是生成可執行檔案的輸出選項。如果我們隻想讓源檔案生成目标檔案(給檔案雖然也是機器代碼但不可執行),可以使用标記-c

,詳細指令如下所示:

$ GCC -c test.c

預設情況下,生成的目标檔案被命名為test.o,但我們也可以為輸出檔案指定名稱,如下所示:

$ GCC -c test.c -o

上面這條指令将編譯後的目标檔案命名為mytest.o,而不是預設的test.o。

迄今為止,我們談論的程式僅涉及到一個源檔案;現實中,一個程式的源代碼通常包含在多個源檔案之中,這該怎麼辦?沒關系,即使這樣,用GCC處理起來也并不複雜,見下例:

$ GCC -o test first.c second.c third.c

要注意的是,要生成可執行程式時,一個程式無論有有一個源檔案還是多個源檔案,所有被編譯和連接配接的源檔案中必須有且僅有一個main函數,因為main函

數是該程式的入口點(換句話說,當系統調用該程式時,首先将控制權授予程式的main函數)。但如果僅僅是把源檔案編譯成目标檔案的時候,因為不會進行連

接,是以main函數不是必需的。

四、常用選項

許多情況下,頭檔案和源檔案會單獨存放在不同的目錄中。例如,假設存放源檔案的子目錄名為./src,而包含檔案則放在層次的其他目錄下,如./inc。當我們在./src

目錄下進行編譯工作時,如何告訴GCC到哪裡找頭檔案呢?方法如下所示:

$ gcc test.c –I../inc -o test

上面的指令告訴GCC包含檔案存放在./inc

目錄下,在目前目錄的上一級。如果在編譯時需要的包含檔案存放在多個目錄下,可以使用多個-I

來指定各個目錄:

$ gcc test.c –I../inc –I../../inc2 -o test

這裡指出了另一個包含子目錄inc2,較之前目錄它還要在再上兩級才能找到。

另外,我們還可以在編譯指令行中定義符号常量。為此,我們可以簡單的在指令行中使用-D選項即可,如下例所示:

$ gcc -DTEST_CONFIGURATION test.c -o test

上面的指令與在源檔案中加入下列指令是等效的:

#define TEST_CONFIGURATION

在編譯指令行中定義符号常量的好處是,不必修改源檔案就能改變由符号常量控制的行為。

五、警告功能

GCC在編譯過程中檢查出錯誤的話,它就會中止編譯;但檢測到警告時卻能繼續編譯生成可執行程式,因為警告隻是針對程式結構的診斷資訊,它不能說明程式一

定有錯誤,而是存在風險,或者可能存在錯誤。雖然GCC提供了非常豐富的警告,但前提是你已經啟用了它們,否則它不會報告這些檢測到的警告。

在衆多的警告選項之中,最常用的就是-Wall選項。該選項能發現程式中一系列的常見錯誤警告,該選項用法舉例如下:

$ gcc -Wall test.c -o test

該選項相當于同時使用了下列所有的選項:

◆unused-function:遇到僅聲明過但尚未定義的靜态函數時發出警告。

◆unused-label:遇到聲明過但不使用的标号的警告。

◆unused-parameter:從未用過的函數參數的警告。

◆unused-variable:在本地聲明但從未用過的變量的警告。

◆unused-value:僅計算但從未用過的值得警告。

◆Format:檢查對printf和scanf等函數的調用,确認各個參數類型和格式串中的一緻。

◆implicit-int:警告沒有規定類型的聲明。

◆implicit-function-:在函數在未經聲明就使用時給予警告。

◆char-subscripts:警告把char類型作為數組下标。這是常見錯誤,程式員經常忘記在某些機器上char有符号。

◆missing-braces:聚合初始化兩邊缺少大括号。

◆Parentheses:在某些情況下如果忽略了括号,編譯器就發出警告。

◆return-type:如果函數定義了傳回類型,而預設類型是int型,編譯器就發出警告。同時警告那些不帶傳回值的

return語句,如果他們所屬的函數并非void類型。

◆sequence-point:出現可疑的代碼元素時,發出報警。

◆Switch:如果某條switch語句的參數屬于枚舉類型,但是沒有對應的case語句使用枚舉元素,編譯器就發出警告(在switch語句中使用default分支能夠防止這個警告)。超出枚舉範圍的case語句同樣會導緻這個警告。

◆strict-aliasing:對變量别名進行最嚴格的檢查。

◆unknown-pragmas:使用了不允許的#pragma。

◆Uninitialized:在初始化之前就使用自動變量。

需要注意的是,各警告選項既然能使之生效,當然也能使之關閉。比如假設我們想要使用-Wall來啟用個選項,同時又要關閉unused警告,利益通過下面的指令來達到目的:

$ gcc -Wall -Wno-unused test.c -o test

下面是使用-Wall選項的時候沒有生效的一些警告項:

◆cast-align:一旦某個指針類型強制轉換時,會導緻目标所需的位址對齊邊界擴充,編譯器就發出警告。例如,某些機器上隻能在2或4位元組邊界上通路整數,如果在這種機型上把char

*強制轉換成int *類型, 編譯器就發出警告。

◆sign-compare:将有符号類型和無符号類型資料進行比較時發出警告。

◆missing-prototypes

:如果沒有預先聲明函數原形就定義了全局函數,編譯器就發出警告。即使函數定義自身提供了函數原形也會産生這個警告。這樣做的目的是檢查沒有在頭檔案中聲明的全局函數。

◆Packed:當結構體帶有packed屬性但實際并沒有出現緊縮式給出警告。

◆Padded:如果結構體通過充填進行對齊則給出警告。

◆unreachable-code:如果發現從未執行的代碼時給出警告。

◆Inline:如果某函數不能内嵌(inline),無論是聲明為inline或者是指定了-finline-functions

選項,編譯器都将發出警告。

◆disabled-optimization:當需要太長時間或過多資源而導緻不能完成某項優化時給出警告。

上面是使用-Wall選項時沒有生效,但又比較常用的一些警告選項。本文中要介紹的最後一個常用警告選項是-Werror。使用該選項後,GCC發現可疑之處時不會簡單的發出警告就算完事,而是将警告作為一個錯誤而中斷編譯過程。該選項在希望得到高品質代碼時非常有用。

六、小結

本文介紹了GCC的基本編譯過程和編譯模式,并詳細闡述了GCC的一些常用選項以及警告功能。這些是在利用GCC進行應用程式設計時最基本也最常用的一些内容,我們會在後續文章中繼續介紹GCC的調試和優化技術。

該指令将同時編譯三個源檔案,即first.c、second.c和

third.c,然後将它們連接配接成一個可執行程式,名為test。

Linux聯盟收集整理 ,轉貼請标明原始連結,如有任何疑問歡迎來本站Linux論壇讨論

http://www.xxlinux.com/linux/article/development/soft/20061029/5551.html

繼續閱讀