Linux编程起步 GCC基本用法
GCC使用入門(一)(1)
http://developer.51cto.com/art/200609/32317.htm
Linux編程起步 GCC基本用法
http://developer.51cto.com/art/200810/94747.htm
詳解GCC的下載和安裝
http://developer.51cto.com/art/200810/94745.htm
一、GCC簡介
通常所說的GCC是GUN Compiler Collection的簡稱,除了編譯程序之外,它還含其他相關(guān)工具,所以它能把易于人類使用的高級語言編寫的源代碼構(gòu)建成計(jì)算機(jī)能夠直接執(zhí)行的二進(jìn)制代碼。GCC是Linux平臺下最常用的編譯程序,它是Linux平臺編譯器的事實(shí)標(biāo)準(zhǔn)。同時(shí),在Linux平臺下的嵌入式開發(fā)領(lǐng)域,GCC也是用得最普遍的一種編譯器。GCC之所以被廣泛采用,是因?yàn)樗苤С指鞣N不同的目標(biāo)體系結(jié)構(gòu)。例如,它既支持基于宿主的開發(fā)(簡單講就是要為某平臺編譯程序,就在該平臺上編譯),也支持交叉編譯(即在A平臺上編譯的程序是供平臺B使用的)。目前,GCC支持的體系結(jié)構(gòu)有四十余種,常見的有X86系列、Arm、PowerPC等。同時(shí),GCC還能運(yùn)行在不同的操作系統(tǒng)上,如Linux、Solaris、Windows等。
| ·詳解GCC的下載和安裝 | |
| ·Linux編程起步 GCC基本用法 |
除了上面講的之外,GCC除了支持C語言外,還支持多種其他語言,例如C++、Ada、Java、Objective-C、FORTRAN、Pascal等。
本系列文章中,我們不僅介紹GCC的基本功能,還涉及到一些諸如優(yōu)化之類的高級功能。另外,我們還考察GCC的一些映像操作工具,如size和objcopy等,這將在后續(xù)的文章中加以介紹。
二、程序的編譯過程
對于GUN編譯器來說,程序的編譯要經(jīng)歷預(yù)處理、編譯、匯編、連接四個(gè)階段,如下圖所示:
?????
從功能上分,預(yù)處理、編譯、匯編是三個(gè)不同的階段,但GCC的實(shí)際操作上,它可以把這三個(gè)步驟合并為一個(gè)步驟來執(zhí)行。下面我們以C語言為例來談一下不同階段的輸入和輸出情況。
在預(yù)處理階段,輸入的是C語言的源文件,通常為*.c。它們通常帶有.h之類頭文件的包含文件。這個(gè)階段主要處理源文件中的#ifdef、 #include和#define命令。該階段會生成一個(gè)中間文件*.i,但實(shí)際工作中通常不用專門生成這種文件,因?yàn)榛旧嫌貌坏?#xff1b;若非要生成這種文件不可,可以利用下面的示例命令:
| gcc -E? test.c -o test.i |
在編譯階段,輸入的是中間文件*.i,編譯后生成匯編語言文件*.s 。這個(gè)階段對應(yīng)的GCC命令如下所示:
| GCC -S test.i -o test.s |
在匯編階段,將輸入的匯編文件*.s轉(zhuǎn)換成機(jī)器語言*.o。這個(gè)階段對應(yīng)的GCC命令如下所示:
| GCC -c test.s -o test.o |
最后,在連接階段將輸入的機(jī)器代碼文件*.s(與其它的機(jī)器代碼文件和庫文件)匯集成一個(gè)可執(zhí)行的二進(jìn)制代碼文件。這一步驟,可以利用下面的示例命令完成:
| GCC test.o -o test |
上面介紹了GCC編譯過程的四個(gè)階段以及相應(yīng)的命令。下面我們進(jìn)一步介紹常用的GCC的模式。
三、GCC常用模式
這里介紹GCC追常用的兩種模式:編譯模式和編譯連接模式。下面以一個(gè)例子來說明各種模式的使用方法。為簡單起見,假設(shè)我們?nèi)康脑创a都在一個(gè)文件test.c中,要想把這個(gè)源文件直接編譯成可執(zhí)行程序,可以使用以下命令:
| $ GCC -o test |
這里test.c是源文件,生成的可執(zhí)行代碼存放在一個(gè)名為test 的文件中(該文件是機(jī)器代碼并且可執(zhí)行)。-o 是生成可執(zhí)行文件的輸出選項(xiàng)。如果我們只想讓源文件生成目標(biāo)文件(給文件雖然也是機(jī)器代碼但不可執(zhí)行),可以使用標(biāo)記-c ,詳細(xì)命令如下所示:
| $ GCC -c test.c |
默認(rèn)情況下,生成的目標(biāo)文件被命名為test.o,但我們也可以為輸出文件指定名稱,如下所示:
| $ GCC -c test.c -o |
上面這條命令將編譯后的目標(biāo)文件命名為mytest.o,而不是默認(rèn)的test.o。
迄今為止,我們談?wù)摰某绦騼H涉及到一個(gè)源文件;現(xiàn)實(shí)中,一個(gè)程序的源代碼通常包含在多個(gè)源文件之中,這該怎么辦?沒關(guān)系,即使這樣,用GCC處理起來也并不復(fù)雜,見下例:
| $ GCC -o test? first.c second.c third.c |
該命令將同時(shí)編譯三個(gè)源文件,即first.c、second.c和 third.c,然后將它們連接成一個(gè)可執(zhí)行程序,名為test。
GCC使用入門(一)(2)
需要注意的是,要生成可執(zhí)行程序時(shí),一個(gè)程序無論有有一個(gè)源文件還是多個(gè)源文件,所有被編譯和連接的源文件中必須有且僅有一個(gè)main函數(shù),因?yàn)閙ain函數(shù)是該程序的入口點(diǎn)(換句話說,當(dāng)系統(tǒng)調(diào)用該程序時(shí),首先將控制權(quán)授予程序的main函數(shù))。但如果僅僅是把源文件編譯成目標(biāo)文件的時(shí)候,因?yàn)椴粫M(jìn)行連接,所以main函數(shù)不是必需的。
四、常用選項(xiàng)
許多情況下,頭文件和源文件會單獨(dú)存放在不同的目錄中。例如,假設(shè)存放源文件的子目錄名為./src,而包含文件則放在層次的其他目錄下,如./inc。當(dāng)我們在./src 目錄下進(jìn)行編譯工作時(shí),如何告訴GCC到哪里找頭文件呢?方法如下所示:
| $ gcc test.c –I../inc -o test |
上面的命令告訴GCC包含文件存放在./inc 目錄下,在當(dāng)前目錄的上一級。如果在編譯時(shí)需要的包含文件存放在多個(gè)目錄下,可以使用多個(gè)-I 來指定各個(gè)目錄:
| $ gcc test.c –I../inc –I../../inc2 -o test |
這里指出了另一個(gè)包含子目錄inc2,較之前目錄它還要在再上兩級才能找到。
另外,我們還可以在編譯命令行中定義符號常量。為此,我們可以簡單的在命令行中使用-D選項(xiàng)即可,如下例所示:
| $ gcc -DTEST_CONFIGURATION test.c -o test |
上面的命令與在源文件中加入下列命令是等效的:
| #define TEST_CONFIGURATION |
在編譯命令行中定義符號常量的好處是,不必修改源文件就能改變由符號常量控制的行為。
五、警告功能
當(dāng)GCC在編譯過程中檢查出錯(cuò)誤的話,它就會中止編譯;但檢測到警告時(shí)卻能繼續(xù)編譯生成可執(zhí)行程序,因?yàn)榫嬷皇轻槍Τ绦蚪Y(jié)構(gòu)的診斷信息,它不能說明程序一定有錯(cuò)誤,而是存在風(fēng)險(xiǎn),或者可能存在錯(cuò)誤。雖然GCC提供了非常豐富的警告,但前提是你已經(jīng)啟用了它們,否則它不會報(bào)告這些檢測到的警告。
在眾多的警告選項(xiàng)之中,最常用的就是-Wall選項(xiàng)。該選項(xiàng)能發(fā)現(xiàn)程序中一系列的常見錯(cuò)誤警告,該選項(xiàng)用法舉例如下:
| $ gcc -Wall test.c -o test |
該選項(xiàng)相當(dāng)于同時(shí)使用了下列所有的選項(xiàng):
◆unused-function:遇到僅聲明過但尚未定義的靜態(tài)函數(shù)時(shí)發(fā)出警告。
◆unused-label:遇到聲明過但不使用的標(biāo)號的警告。
◆unused-parameter:從未用過的函數(shù)參數(shù)的警告。
◆unused-variable:在本地聲明但從未用過的變量的警告。
◆unused-value:僅計(jì)算但從未用過的值得警告。
◆Format:檢查對printf和scanf等函數(shù)的調(diào)用,確認(rèn)各個(gè)參數(shù)類型和格式串中的一致。
◆implicit-int:警告沒有規(guī)定類型的聲明。
◆implicit-function-:在函數(shù)在未經(jīng)聲明就使用時(shí)給予警告。
◆char-subscripts:警告把char類型作為數(shù)組下標(biāo)。這是常見錯(cuò)誤,程序員經(jīng)常忘記在某些機(jī)器上char有符號。
◆missing-braces:聚合初始化兩邊缺少大括號。
◆Parentheses:在某些情況下如果忽略了括號,編譯器就發(fā)出警告。
◆return-type:如果函數(shù)定義了返回類型,而默認(rèn)類型是int型,編譯器就發(fā)出警告。同時(shí)警告那些不帶返回值的 return語句,如果他們所屬的函數(shù)并非void類型。
◆sequence-point:出現(xiàn)可疑的代碼元素時(shí),發(fā)出報(bào)警。
◆Switch:如果某條switch語句的參數(shù)屬于枚舉類型,但是沒有對應(yīng)的case語句使用枚舉元素,編譯器就發(fā)出警告(在switch語句中使用default分支能夠防止這個(gè)警告)。超出枚舉范圍的case語句同樣會導(dǎo)致這個(gè)警告。
◆strict-aliasing:對變量別名進(jìn)行最嚴(yán)格的檢查。
◆unknown-pragmas:使用了不允許的#pragma。
◆Uninitialized:在初始化之前就使用自動變量。
需要注意的是,各警告選項(xiàng)既然能使之生效,當(dāng)然也能使之關(guān)閉。比如假設(shè)我們想要使用-Wall來啟用個(gè)選項(xiàng),同時(shí)又要關(guān)閉unused警告,利益通過下面的命令來達(dá)到目的:
| $ gcc -Wall -Wno-unused test.c -o test |
下面是使用-Wall選項(xiàng)的時(shí)候沒有生效的一些警告項(xiàng):
◆cast-align:一旦某個(gè)指針類型強(qiáng)制轉(zhuǎn)換時(shí),會導(dǎo)致目標(biāo)所需的地址對齊邊界擴(kuò)展,編譯器就發(fā)出警告。例如,某些機(jī)器上只能在2或4字節(jié)邊界上訪問整數(shù),如果在這種機(jī)型上把char *強(qiáng)制轉(zhuǎn)換成int *類型, 編譯器就發(fā)出警告。
◆sign-compare:將有符號類型和無符號類型數(shù)據(jù)進(jìn)行比較時(shí)發(fā)出警告。
◆missing-prototypes :如果沒有預(yù)先聲明函數(shù)原形就定義了全局函數(shù),編譯器就發(fā)出警告。即使函數(shù)定義自身提供了函數(shù)原形也會產(chǎn)生這個(gè)警告。這樣做的目的是檢查沒有在頭文件中聲明的全局函數(shù)。
◆Packed:當(dāng)結(jié)構(gòu)體帶有packed屬性但實(shí)際并沒有出現(xiàn)緊縮式給出警告。
◆Padded:如果結(jié)構(gòu)體通過充填進(jìn)行對齊則給出警告。
◆unreachable-code:如果發(fā)現(xiàn)從未執(zhí)行的代碼時(shí)給出警告。
◆Inline:如果某函數(shù)不能內(nèi)嵌(inline),無論是聲明為inline或者是指定了-finline-functions 選項(xiàng),編譯器都將發(fā)出警告。?
◆disabled-optimization:當(dāng)需要太長時(shí)間或過多資源而導(dǎo)致不能完成某項(xiàng)優(yōu)化時(shí)給出警告。
上面是使用-Wall選項(xiàng)時(shí)沒有生效,但又比較常用的一些警告選項(xiàng)。本文中要介紹的最后一個(gè)常用警告選項(xiàng)是-Werror。使用該選項(xiàng)后,GCC發(fā)現(xiàn)可疑之處時(shí)不會簡單的發(fā)出警告就算完事,而是將警告作為一個(gè)錯(cuò)誤而中斷編譯過程。該選項(xiàng)在希望得到高質(zhì)量代碼時(shí)非常有用。
六、小結(jié)
本文介紹了GCC的基本編譯過程和編譯模式,并詳細(xì)闡述了GCC的一些常用選項(xiàng)以及警告功能。這些是在利用GCC進(jìn)行應(yīng)用編程時(shí)最基本也最常用的一些內(nèi)容,我們會在后續(xù)文章中繼續(xù)介紹GCC的調(diào)試和優(yōu)化技術(shù)。
Linux編程起步 GCC基本用法
初學(xué)時(shí)最好從命令行入手,這樣可以熟悉從編寫程序、編譯、調(diào)試和執(zhí)行的整個(gè)過程。編寫程序可以用vi或其它編輯器編寫。編譯則使用GCC命令。要往下學(xué)習(xí)首先就得熟悉GCC命令的用法。
AD:2013云計(jì)算架構(gòu)師峰會課程資料下載
初學(xué)時(shí)最好從命令行入手,這樣可以熟悉從編寫程序、編譯、調(diào)試和執(zhí)行的整個(gè)過程。編寫程序可以用vi或其它編輯器編寫。編譯則使用GCC命令。要往下學(xué)習(xí)首先就得熟悉GCC命令的用法。
GCC命令提供了非常多的命令選項(xiàng),但并不是所有都要熟悉,初學(xué)時(shí)掌握幾個(gè)常用的就可以了,到后面再慢慢學(xué)習(xí)其它選項(xiàng),免得因選項(xiàng)太多而打擊了學(xué)習(xí)的信心。
一. 常用編譯命令選項(xiàng)
假設(shè)源程序文件名為test.c。
1. 無選項(xiàng)編譯鏈接
用法:#gcc test.c
作用:將test.c預(yù)處理、匯編、編譯并鏈接形成可執(zhí)行文件。這里未指定輸出文件,默認(rèn)輸出為a.out。
2. 選項(xiàng) -o
用法:#gcc test.c -o test
作用:將test.c預(yù)處理、匯編、編譯并鏈接形成可執(zhí)行文件test。-o選項(xiàng)用來指定輸出文件的文件名。
3. 選項(xiàng) -E
用法:#gcc -E test.c -o test.i
作用:將test.c預(yù)處理輸出test.i文件。
4. 選項(xiàng) -S
用法:#gcc -S test.i
作用:將預(yù)處理輸出文件test.i匯編成test.s文件。
5. 選項(xiàng) -c
用法:#gcc -c test.s
作用:將匯編輸出文件test.s編譯輸出test.o文件。
6. 無選項(xiàng)鏈接
用法:#gcc test.o -o test
作用:將編譯輸出文件test.o鏈接成最終可執(zhí)行文件test。
7. 選項(xiàng)-O
用法:#gcc -O1 test.c -o test
作用:使用編譯優(yōu)化級別1編譯程序。級別為1~3,級別越大優(yōu)化效果越好,但編譯時(shí)間越長。
二. 多源文件的編譯方法
如果有多個(gè)源文件,基本上有兩種編譯方法:
[假設(shè)有兩個(gè)源文件為test.c和testfun.c]
1. 多個(gè)文件一起編譯
用法:#gcc testfun.c test.c -o test
作用:將testfun.c和test.c分別編譯后鏈接成test可執(zhí)行文件。
2. 分別編譯各個(gè)源文件,之后對編譯后輸出的目標(biāo)文件鏈接。
用法:
#gcc -c testfun.c //將testfun.c編譯成testfun.o
#gcc -c test.c?? //將test.c編譯成test.o
#gcc -o testfun.o test.o -o test //將testfun.o和test.o鏈接成test
以上兩種方法相比較,第一中方法編譯時(shí)需要所有文件重新編譯,而第二種方法可以只重新編譯修改的文件,未修改的文件不用重新編譯。
總結(jié)
以上是生活随笔為你收集整理的Linux编程起步 GCC基本用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 六字诀养生法 气功口诀
- 下一篇: 小心你的Python程序,它会是你的一面