嵌入式Linux下最常用的C語言編譯器GCC命令詳解

GCC(GNU Compiler Collection)是Linux下最常用的C語言編譯器,是GNU項(xiàng)目中符合ANSI C標(biāo)準(zhǔn)的編譯系統(tǒng),能夠編譯用C、C++和Object C等語言編寫的程序。同時(shí)它可以通過不同的前端模塊來支持各種語言,如Java、Fortran、Pascal、Modula-3和Ada等。

穿插一個(gè)玩笑: GNU意思是GNU’s not Unix而非角馬。然而GNU還是一個(gè)未拆分的連詞,這其實(shí)是一個(gè)源于hacker的幽默:GNU是一個(gè)回文游戲,第一個(gè)字母G是湊數(shù)的,你當(dāng)然可以叫他做ANU或者BNU。下面開始。

一.CC編譯程序過程分四個(gè)階段

◆ 預(yù)處理(Pre-Processing)

◆ 編譯(Compiling)

◆ 匯編(Assembling)

◆ 鏈接(Linking)

Linux程序員可以根據(jù)自己的需要讓GCC在編譯的任何階段結(jié)束轉(zhuǎn)去檢查或使用編譯器在該階段的輸出信息,或者對(duì)最后生成的二進(jìn)制文件進(jìn)行控制,以便通過加入不同數(shù)量和種類的調(diào)試代碼來為今后的調(diào)試做好準(zhǔn)備。如同其他的編譯器,GCC也提供了靈活而強(qiáng)大的代碼優(yōu)化功能,利用它可以生成執(zhí)行效率更高的代碼。

GCC提供了30多條警告信息和三個(gè)警告級(jí)別,使用它們有助于增強(qiáng)程序的穩(wěn)定性和可移植性。此外,GCC還對(duì)標(biāo)準(zhǔn)的C和C++語言進(jìn)行了大量的擴(kuò)展,提高程序的執(zhí)行效率,有助于編譯器進(jìn)行代碼優(yōu)化,能夠減輕編程的工作量。

二.簡(jiǎn)單編譯命令

我們以Hello world程序來開始我們的學(xué)習(xí)。代碼如下:

/* hello.c */

#include?

int main(void)

{

printf ("Hello world!\n");

return 0;

}

1. 執(zhí)行如下命令:$ gcc -o hello hello.c

運(yùn)行如下 : $ ./hello

輸出: Hello,world!

2. 我們也可以分步編譯如下:

(1) $ gcc –E hello.c -o hello.i

//預(yù)處理結(jié)束

//這時(shí)候你看一下hello.i ,可以看到插進(jìn)去了很多東西。

(2) $ gcc –S hello.i

//生成匯編代碼后結(jié)束

(3) $ gcc –c hello.c

或者:

$ gcc -c hello.c –o hello.o

或者:

$ gcc -c hello.i -o hello.o

//編譯結(jié)束

//生成 hello.o文件

(4) $ gcc hello.o –o hello.o

或者:

$ gcc –o hello hello.c

//鏈接完畢,生成可執(zhí)行代碼

3. 我們可以把幾個(gè)文件一同編譯生成同一個(gè)可執(zhí)行文件。

比如:一個(gè)工程有main.c foo.c def.c生成foo的可執(zhí)行文件。

編譯命令如下:

$ gcc –c main.c foo.c def.c –o foo

或者:

$ gcc –o foo main.c foo.c def.c

三.庫依賴

函數(shù)庫是一些頭文件(.h)和庫文件(.so或者.a)的集合。Linux下的大多數(shù)函數(shù)都默認(rèn)將頭文件放到/usr/include/目錄下,而庫文件則放到/usr/lib/目錄下,但并非絕對(duì)如此。因此GCC設(shè)有添加頭文件和庫文件的編譯選項(xiàng)開關(guān)。

1. 添加頭文件:-I

例如在/home/work/include/目錄下有編譯foo.c所需頭文件def.h,為了讓GCC能找到它們,就需要使用-I選項(xiàng):

$ gcc foo.c -I /home/work/include/def.h -o foo

2. 添加庫文件:-L

例如在/home/work/lib/目錄下有鏈接所需庫文件libdef.so,為了讓GCC能找到它們,就需要使用-L選項(xiàng):

$ gcc foo.c –L /home/work/lib –ldef.a –o foo

說明:-l選項(xiàng)指示GCC去連接庫文件libdef.so。Linux下的庫文件命名有一個(gè)約定,即庫文件以lib三個(gè)字母開頭,因?yàn)樗械膸煳募甲裱@個(gè)約定,故在用-l選項(xiàng)指定鏈接的庫文件名時(shí)可以省去lib三個(gè)字母。

題外語:

Linux下的庫文件分為動(dòng)態(tài)鏈接庫(.so文件)和靜態(tài)鏈接庫(.a文件)。GCC默認(rèn)為動(dòng)態(tài)庫優(yōu)先,若想在動(dòng)態(tài)庫和靜態(tài)庫同時(shí)存在的時(shí)候鏈接靜態(tài)庫需要指明為-static選項(xiàng)。比如上例中如還有一個(gè)libdef.a而你想鏈接libdef.a時(shí)候命令如下:

$ gcc foo.c –L /home/work/lib –static –ldef.a –o foo

四.代碼優(yōu)化

GCC提供不同程度的代碼優(yōu)化功能。開關(guān)選項(xiàng)是:-On,n取值為0到3。默認(rèn)為1。-O0表示沒有優(yōu)化,而-O3是最高優(yōu)化。優(yōu)化級(jí)別越高代碼運(yùn)行越快,但并不是所有代碼都能夠加載最高優(yōu)化,而應(yīng)該視具體情況而定。但一般都使用-O2選項(xiàng),因?yàn)樗趦?yōu)化長(zhǎng)度、編譯時(shí)間和代碼大小之間,取得了一個(gè)比較理想的平衡點(diǎn)。

以下這段說的比較詳細(xì):

編譯時(shí)使用選項(xiàng)-O可以告訴GCC同時(shí)減小代碼的長(zhǎng)度和執(zhí)行時(shí)間,其效果等價(jià)于-O1。在這一級(jí)別上能夠進(jìn)行的優(yōu)化類型雖然取決于目標(biāo)處理器,但一般都會(huì)包括線程跳轉(zhuǎn)(Thread Jump)和延遲退棧(Deferred Stack Pops)兩種優(yōu)化。選項(xiàng)-O2告訴GCC除了完成所有-O1級(jí)別的優(yōu)化之外,同時(shí)還要進(jìn)行一些額外的調(diào)整工作,如處理器指令調(diào)度等。選項(xiàng)-O3則除了完成所有-O2級(jí)別的優(yōu)化之外,還包括循環(huán)展開和其它一些與處理器特性相關(guān)的優(yōu)化工作。通常來說,數(shù)字越大優(yōu)化的等級(jí)越高,同時(shí)也就意味著程序的運(yùn)行速度越快。

下面通過具體實(shí)例來感受一下GCC的代碼優(yōu)化功能,所用程序如清單3所示。

/* optimize.c */

#include

int main(void)

{

double counter;

double result;

double temp;

for (counter = 0;

counter < 2000.0 * 2000.0 * 2000.0 / 20.0 + 2020;

counter += (5 - 1) / 4) {

temp = counter / 1979;

result = counter;

}

printf("Result is %lf\n", result);

return 0;

}

首先不加任何優(yōu)化選項(xiàng)進(jìn)行編譯:

# gcc -Wall optimize.c -o optimize

借助Linux提供的time命令,可以大致統(tǒng)計(jì)出該程序在運(yùn)行時(shí)所需要的時(shí)間:

# time ./optimize

Result is 400002019.000000

real 0m14.942s

user 0m14.940s

sys 0m0.000s

接下去使用優(yōu)化選項(xiàng)來對(duì)代碼進(jìn)行優(yōu)化處理:

# gcc -Wall -O optimize.c -o optimize

在同樣的條件下再次測(cè)試一下運(yùn)行時(shí)間:

# time ./optimize

Result is 400002019.000000

real 0m3.256s

user 0m3.240s

sys 0m0.000s

對(duì)比兩次執(zhí)行的輸出結(jié)果不難看出,程序的性能的確得到了很大幅度的改善,由原來的14秒縮短到了3秒。這個(gè)例子是專門針對(duì)GCC的優(yōu)化功能而設(shè)計(jì)的,因此優(yōu)化前后程序的執(zhí)行速度發(fā)生了很大的改變。盡管GCC的代碼優(yōu)化功能非常強(qiáng)大,但作為一名優(yōu)秀的Linux程序員,首先還是要力求能夠手工編寫出高質(zhì)量的代碼。如果編寫的代碼簡(jiǎn)短,并且邏輯性強(qiáng),編譯器就不會(huì)做更多的工作,甚至根本用不著優(yōu)化。

優(yōu)化雖然能夠給程序帶來更好的執(zhí)行性能,但在如下一些場(chǎng)合中應(yīng)該避免優(yōu)化代碼:

◆ 程序開發(fā)的時(shí)候優(yōu)化等級(jí)越高,消耗在編譯上的時(shí)間就越長(zhǎng),因此在開發(fā)的時(shí)候最好不要使用優(yōu)化選項(xiàng),只有到軟件發(fā)行或開發(fā)結(jié)束的時(shí)候,才考慮對(duì)最終生成的代碼進(jìn)行優(yōu)化。

◆ 資源受限的時(shí)候一些優(yōu)化選項(xiàng)會(huì)增加可執(zhí)行代碼的體積,如果程序在運(yùn)行時(shí)能夠申請(qǐng)到的內(nèi)存資源非常緊張(如一些實(shí)時(shí)嵌入式設(shè)備),那就不要對(duì)代碼進(jìn)行優(yōu)化,因?yàn)橛蛇@帶來的負(fù)面影響可能會(huì)產(chǎn)生非常嚴(yán)重的后果。

◆ 跟蹤調(diào)試的時(shí)候在對(duì)代碼進(jìn)行優(yōu)化的時(shí)候,某些代碼可能會(huì)被刪除或改寫,或者為了取得更佳的性能而進(jìn)行重組,從而使跟蹤和調(diào)試變得異常困難。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • GCC編譯器 GCC是一個(gè)交叉平臺(tái)的編譯器,我想大家并不會(huì)覺得陌生。C/C++開發(fā)的時(shí)候很多時(shí)候都會(huì)用到GCC來進(jìn)...
    故事狗閱讀 9,570評(píng)論 0 25
  • 1.簡(jiǎn)介 GCC 的意思也只是 GNU C Compiler 而已。經(jīng)過了這么多年的發(fā)展,GCC 已經(jīng)不僅僅能支持...
    Leon_Geo閱讀 771評(píng)論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • pwd返回了根目錄 這時(shí)候看到系統(tǒng)返回了一個(gè) /,這個(gè) / 被我們稱為系統(tǒng)的 根目錄(root),這個(gè)位置也就是我...
    夏威夷的芒果閱讀 1,181評(píng)論 0 1
  • 一個(gè)古樸的村莊里,一群人架著攝像機(jī)圍著一個(gè)英俊的男子,好似在拍攝什么。剛拍完歇息的時(shí)候,一個(gè)經(jīng)紀(jì)人拿著稿子走到那男...
    若果閱讀 675評(píng)論 1 1

友情鏈接更多精彩內(nèi)容