青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Impossible is nothing  
  愛(ài)過(guò)知情重醉過(guò)知酒濃   花開(kāi)花謝終是空   緣份不停留像春風(fēng)來(lái)又走   女人如花花似夢(mèng)
公告
日歷
<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
統(tǒng)計(jì)
  • 隨筆 - 8
  • 文章 - 91
  • 評(píng)論 - 16
  • 引用 - 0

導(dǎo)航

常用鏈接

留言簿(4)

隨筆分類(lèi)(4)

隨筆檔案(8)

文章分類(lèi)(77)

文章檔案(91)

相冊(cè)

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

 

在為L(zhǎng)inux開(kāi)發(fā)應(yīng)用程序時(shí),絕大多數(shù)情況下使用的都是C語(yǔ)言,因此幾乎每一位Linux程序員面臨的首要問(wèn)題都是如何靈活運(yùn)用C編譯器。目前 Linux下最常用的C語(yǔ)言編譯器是GCC(GNU Compiler Collection),它是GNU項(xiàng)目中符合ANSI C標(biāo)準(zhǔn)的編譯系統(tǒng),能夠編譯用C、C++和Object C等語(yǔ)言編寫(xiě)的程序。GCC不僅功能非常強(qiáng)大,結(jié)構(gòu)也異常靈活。最值得稱(chēng)道的一點(diǎn)就是它可以通過(guò)不同的前端模塊來(lái)支持各種語(yǔ)言,如Java、 Fortran、Pascal、Modula-3和Ada等。

開(kāi)放、自由和靈活是Linux的魅力所在,而這一點(diǎn)在GCC上的體現(xiàn)就是程序員通過(guò)它能夠更好地控制整個(gè)編譯過(guò)程。在使用GCC編譯程序時(shí),編譯過(guò)程可以被細(xì)分為四個(gè)階段:

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

◆ 編譯(Compiling)

◆ 匯編(Assembling)

◆ 鏈接(Linking)

Linux 程序員可以根據(jù)自己的需要讓GCC在編譯的任何階段結(jié)束,以便檢查或使用編譯器在該階段的輸出信息,或者對(duì)最后生成的二進(jìn)制文件進(jìn)行控制,以便通過(guò)加入不同數(shù)量和種類(lèi)的調(diào)試代碼來(lái)為今后的調(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++語(yǔ)言進(jìn)行了大量的擴(kuò)展,提高程序的執(zhí)行效率,有助于編譯器進(jìn)行代碼優(yōu)化,能夠減輕編程的工作量。

GCC起步

在學(xué)習(xí)使用GCC之前,下面的這個(gè)例子能夠幫助用戶(hù)迅速理解GCC的工作原理,并將其立即運(yùn)用到實(shí)際的項(xiàng)目開(kāi)發(fā)中去。首先用熟悉的編輯器輸入清單1所示的代碼:

清單1:hello.c

#include <stdio.h>
int main(void)
{
printf ("Hello world, Linux programming!n");
return 0;
}

然后執(zhí)行下面的命令編譯和運(yùn)行這段程序:

# gcc hello.c -o hello
# ./hello
Hello world, Linux programming!

從程序員的角度看,只需簡(jiǎn)單地執(zhí)行一條GCC命令就可以了,但從編譯器的角度來(lái)看,卻需要完成一系列非常繁雜的工作。首先,GCC需要調(diào)用預(yù)處理程序 cpp,由它負(fù)責(zé)展開(kāi)在源文件中定義的宏,并向其中插入“#include”語(yǔ)句所包含的內(nèi)容;接著,GCC會(huì)調(diào)用ccl和as將處理后的源代碼編譯成目標(biāo)代碼;最后,GCC會(huì)調(diào)用鏈接程序ld,把生成的目標(biāo)代碼鏈接成一個(gè)可執(zhí)行程序。

為了更好地理解GCC的工作過(guò)程,可以把上述編譯過(guò)程分成幾個(gè)步驟單獨(dú)進(jìn)行,并觀察每步的運(yùn)行結(jié)果。第一步是進(jìn)行預(yù)編譯,使用-E參數(shù)可以讓GCC在預(yù)處理結(jié)束后停止編譯過(guò)程:

#  gcc -E hello.c -o hello.i

此時(shí)若查看hello.cpp文件中的內(nèi)容,會(huì)發(fā)現(xiàn)stdio.h的內(nèi)容確實(shí)都插到文件里去了,而其它應(yīng)當(dāng)被預(yù)處理的宏定義也都做了相應(yīng)的處理。下一步是將hello.i編譯為目標(biāo)代碼,這可以通過(guò)使用-c參數(shù)來(lái)完成:

#  gcc -c hello.i -o hello.o

GCC默認(rèn)將.i文件看成是預(yù)處理后的C語(yǔ)言源代碼,因此上述命令將自動(dòng)跳過(guò)預(yù)處理步驟而開(kāi)始執(zhí)行編譯過(guò)程,也可以使用-x參數(shù)讓GCC從指定的步驟開(kāi)始編譯。最后一步是將生成的目標(biāo)文件鏈接成可執(zhí)行文件:

#  gcc hello.o -o hello

在采用模塊化的設(shè)計(jì)思想進(jìn)行軟件開(kāi)發(fā)時(shí),通常整個(gè)程序是由多個(gè)源文件組成的,相應(yīng)地也就形成了多個(gè)編譯單元,使用GCC能夠很好地管理這些編譯單元。假設(shè)有一個(gè)由foo1.c和foo2.c兩個(gè)源文件組成的程序,為了對(duì)它們進(jìn)行編譯,并最終生成可執(zhí)行程序foo,可以使用下面這條命令:

#  gcc foo1.c foo2.c -o foo

如果同時(shí)處理的文件不止一個(gè),GCC仍然會(huì)按照預(yù)處理、編譯和鏈接的過(guò)程依次進(jìn)行。如果深究起來(lái),上面這條命令大致相當(dāng)于依次執(zhí)行如下三條命令:

# gcc -c foo1.c -o foo1.o
# gcc -c foo2.c -o foo2.o
# gcc foo1.o foo2.o -o foo

在編譯一個(gè)包含許多源文件的工程時(shí),若只用一條GCC命令來(lái)完成編譯是非常浪費(fèi)時(shí)間的。假設(shè)項(xiàng)目中有100個(gè)源文件需要編譯,并且每個(gè)源文件中都包含 10000行代碼,如果像上面那樣僅用一條GCC命令來(lái)完成編譯工作,那么GCC需要將每個(gè)源文件都重新編譯一遍,然后再全部連接起來(lái)。很顯然,這樣浪費(fèi)的時(shí)間相當(dāng)多,尤其是當(dāng)用戶(hù)只是修改了其中某一個(gè)文件的時(shí)候,完全沒(méi)有必要將每個(gè)文件都重新編譯一遍,因?yàn)楹芏嘁呀?jīng)生成的目標(biāo)文件是不會(huì)改變的。要解決這個(gè)問(wèn)題,關(guān)鍵是要靈活運(yùn)用GCC,同時(shí)還要借助像Make這樣的工具。

警告提示功能

GCC包含完整的出錯(cuò)檢查和警告提示功能,它們可以幫助Linux程序員寫(xiě)出更加專(zhuān)業(yè)和優(yōu)美的代碼。先來(lái)讀讀清單2所示的程序,這段代碼寫(xiě)得很糟糕,仔細(xì)檢查一下不難挑出很多毛病:

◆main函數(shù)的返回值被聲明為void,但實(shí)際上應(yīng)該是int;

◆使用了GNU語(yǔ)法擴(kuò)展,即使用long long來(lái)聲明64位整數(shù),不符合ANSI/ISO C語(yǔ)言標(biāo)準(zhǔn);

◆main函數(shù)在終止前沒(méi)有調(diào)用return語(yǔ)句。

清單2:illcode.c

#include <stdio.h>
void main(void)
{
  long long int var = 1;
  printf("It is not standard C code!n");
}

下面來(lái)看看GCC是如何幫助程序員來(lái)發(fā)現(xiàn)這些錯(cuò)誤的。當(dāng)GCC在編譯不符合ANSI/ISO C語(yǔ)言標(biāo)準(zhǔn)的源代碼時(shí),如果加上了-pedantic選項(xiàng),那么使用了擴(kuò)展語(yǔ)法的地方將產(chǎn)生相應(yīng)的警告信息:

# gcc -pedantic illcode.c -o illcode
illcode.c: In function `main':
illcode.c:9: ISO C89 does not support `long long'
illcode.c:8: return type of `main' is not `int'

需要注意的是,-pedantic編譯選項(xiàng)并不能保證被編譯程序與ANSI/ISO C標(biāo)準(zhǔn)的完全兼容,它僅僅只能用來(lái)幫助Linux程序員離這個(gè)目標(biāo)越來(lái)越近。或者換句話(huà)說(shuō),-pedantic選項(xiàng)能夠幫助程序員發(fā)現(xiàn)一些不符合 ANSI/ISO C標(biāo)準(zhǔn)的代碼,但不是全部,事實(shí)上只有ANSI/ISO C語(yǔ)言標(biāo)準(zhǔn)中要求進(jìn)行編譯器診斷的那些情況,才有可能被GCC發(fā)現(xiàn)并提出警告。

除了-pedantic之外,GCC還有一些其它編譯選項(xiàng)也能夠產(chǎn)生有用的警告信息。這些選項(xiàng)大多以-W開(kāi)頭,其中最有價(jià)值的當(dāng)數(shù)-Wall了,使用它能夠使GCC產(chǎn)生盡可能多的警告信息:

# gcc -Wall illcode.c -o illcode
illcode.c:8: warning: return type of `main' is not `int'
illcode.c: In function `main':
illcode.c:9: warning: unused variable `var'

GCC給出的警告信息雖然從嚴(yán)格意義上說(shuō)不能算作是錯(cuò)誤,但卻很可能成為錯(cuò)誤的棲身之所。一個(gè)優(yōu)秀的Linux程序員應(yīng)該盡量避免產(chǎn)生警告信息,使自己的代碼始終保持簡(jiǎn)潔、優(yōu)美和健壯的特性。

在處理警告方面,另一個(gè)常用的編譯選項(xiàng)是-Werror,它要求GCC將所有的警告當(dāng)成錯(cuò)誤進(jìn)行處理,這在使用自動(dòng)編譯工具(如Make等)時(shí)非常有用。如果編譯時(shí)帶上-Werror選項(xiàng),那么GCC會(huì)在所有產(chǎn)生警告的地方停止編譯,迫使程序員對(duì)自己的代碼進(jìn)行修改。只有當(dāng)相應(yīng)的警告信息消除時(shí),才可能將編譯過(guò)程繼續(xù)朝前推進(jìn)。執(zhí)行情況如下:

# gcc -Wall -Werror illcode.c -o illcode
cc1: warnings being treated as errors
illcode.c:8: warning: return type of `main' is not `int'
illcode.c: In function `main':
illcode.c:9: warning: unused variable `var'

對(duì)Linux程序員來(lái)講,GCC給出的警告信息是很有價(jià)值的,它們不僅可以幫助程序員寫(xiě)出更加健壯的程序,而且還是跟蹤和調(diào)試程序的有力工具。建議在用GCC編譯源代碼時(shí)始終帶上-Wall選項(xiàng),并把它逐漸培養(yǎng)成為一種習(xí)慣,這對(duì)找出常見(jiàn)的隱式編程錯(cuò)誤很有幫助。

在Linux 下開(kāi)發(fā)軟件時(shí),完全不使用第三方函數(shù)庫(kù)的情況是比較少見(jiàn)的,通常來(lái)講都需要借助一個(gè)或多個(gè)函數(shù)庫(kù)的支持才能夠完成相應(yīng)的功能。從程序員的角度看,函數(shù)庫(kù)實(shí)際上就是一些頭文件(.h)和庫(kù)文件(.so或者.a)的集合。雖然Linux下的大多數(shù)函數(shù)都默認(rèn)將頭文件放到/usr/include/目錄下,而庫(kù)文件則放到/usr/lib/目錄下,但并不是所有的情況都是這樣。正因如此,GCC在編譯時(shí)必須有自己的辦法來(lái)查找所需要的頭文件和庫(kù)文件。

GCC采用搜索目錄的辦法來(lái)查找所需要的文件,-I選項(xiàng)可以向GCC的頭文件搜索路徑中添加新的目錄。例如,如果在/home/xiaowp/include/目錄下有編譯時(shí)所需要的頭文件,為了讓GCC能夠順利地找到它們,就可以使用-I選項(xiàng):

# gcc foo.c -I /home/xiaowp/include -o foo

同樣,如果使用了不在標(biāo)準(zhǔn)位置的庫(kù)文件,那么可以通過(guò)-L選項(xiàng)向GCC的庫(kù)文件搜索路徑中添加新的目錄。例如,如果在/home/xiaowp/lib/目錄下有鏈接時(shí)所需要的庫(kù)文件libfoo.so,為了讓GCC能夠順利地找到它,可以使用下面的命令:

# gcc foo.c -L /home/xiaowp/lib -lfoo -o foo

值得好好解釋一下的是-l選項(xiàng),它指示GCC去連接庫(kù)文件libfoo.so。Linux下的庫(kù)文件在命名時(shí)有一個(gè)約定,那就是應(yīng)該以lib三個(gè)字母開(kāi)頭,由于所有的庫(kù)文件都遵循了同樣的規(guī)范,因此在用-l選項(xiàng)指定鏈接的庫(kù)文件名時(shí)可以省去lib三個(gè)字母,也就是說(shuō)GCC在對(duì)-lfoo進(jìn)行處理時(shí),會(huì)自動(dòng)去鏈接名為libfoo.so的文件。

Linux下的庫(kù)文件分為兩大類(lèi)分別是動(dòng)態(tài)鏈接庫(kù)(通常以.so結(jié)尾)和靜態(tài)鏈接庫(kù)(通常以.a 結(jié)尾),兩者的差別僅在程序執(zhí)行時(shí)所需的代碼是在運(yùn)行時(shí)動(dòng)態(tài)加載的,還是在編譯時(shí)靜態(tài)加載的。默認(rèn)情況下,GCC在鏈接時(shí)優(yōu)先使用動(dòng)態(tài)鏈接庫(kù),只有當(dāng)動(dòng)態(tài)鏈接庫(kù)不存在時(shí)才考慮使用靜態(tài)鏈接庫(kù),如果需要的話(huà)可以在編譯時(shí)加上-static選項(xiàng),強(qiáng)制使用靜態(tài)鏈接庫(kù)。例如,如果在 /home/xiaowp/lib/目錄下有鏈接時(shí)所需要的庫(kù)文件libfoo.so和libfoo.a,為了讓GCC在鏈接時(shí)只用到靜態(tài)鏈接庫(kù),可以使用下面的命令:

# gcc foo.c -L /home/xiaowp/lib -static -lfoo -o foo
代碼優(yōu)化

代碼優(yōu)化指的是編譯器通過(guò)分析源代碼,找出其中尚未達(dá)到最優(yōu)的部分,然后對(duì)其重新進(jìn)行組合,目的是改善程序的執(zhí)行性能。GCC提供的代碼優(yōu)化功能非常強(qiáng)大,它通過(guò)編譯選項(xiàng)-On來(lái)控制優(yōu)化代碼的生成,其中n是一個(gè)代表優(yōu)化級(jí)別的整數(shù)。對(duì)于不同版本的GCC來(lái)講,n的取值范圍及其對(duì)應(yīng)的優(yōu)化效果可能并不完全相同,比較典型的范圍是從0變化到2或3。

編譯時(shí)使用選項(xiàng)-O可以告訴GCC同時(shí)減小代碼的長(zhǎng)度和執(zhí)行時(shí)間,其效果等價(jià)于-O1。在這一級(jí)別上能夠進(jìn)行的優(yōu)化類(lèi)型雖然取決于目標(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)展開(kāi)和其它一些與處理器特性相關(guān)的優(yōu)化工作。通常來(lái)說(shuō),數(shù)字越大優(yōu)化的等級(jí)越高,同時(shí)也就意味著程序的運(yùn)行速度越快。許多Linux程序員都喜歡使用-O2選項(xiàng),因?yàn)樗趦?yōu)化長(zhǎng)度、編譯時(shí)間和代碼大小之間,取得了一個(gè)比較理想的平衡點(diǎn)。

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

清單3:optimize.c

#include <stdio.h>

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 %lfn", 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 ./optimizeResult is 400002019.000000real    0m14.942suser    0m14.940ssys     0m0.000s

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

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

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

# time ./optimizeResult is 400002019.000000real    0m3.256suser    0m3.240ssys     0m0.000s

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

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

◆ 程序開(kāi)發(fā)的時(shí)候 優(yōu)化等級(jí)越高,消耗在編譯上的時(shí)間就越長(zhǎng),因此在開(kāi)發(fā)的時(shí)候最好不要使用優(yōu)化選項(xiàng),只有到軟件發(fā)行或開(kāi)發(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)橛蛇@帶來(lái)的負(fù)面影響可能會(huì)產(chǎn)生非常嚴(yán)重的后果。

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

調(diào)試

一個(gè)功能強(qiáng)大的調(diào)試器不僅為程序員提供了跟蹤程序執(zhí)行的手段,而且還可以幫助程序員找到解決問(wèn)題的方法。對(duì)于Linux程序員來(lái)講,GDB(GNU Debugger)通過(guò)與GCC的配合使用,為基于Linux的軟件開(kāi)發(fā)提供了一個(gè)完善的調(diào)試環(huán)境。

默認(rèn)情況下,GCC在編譯時(shí)不會(huì)將調(diào)試符號(hào)插入到生成的二進(jìn)制代碼中,因?yàn)檫@樣會(huì)增加可執(zhí)行文件的大小。如果需要在編譯時(shí)生成調(diào)試符號(hào)信息,可以使用GCC 的-g或者-ggdb選項(xiàng)。GCC在產(chǎn)生調(diào)試符號(hào)時(shí),同樣采用了分級(jí)的思路,開(kāi)發(fā)人員可以通過(guò)在-g選項(xiàng)后附加數(shù)字1、2或3來(lái)指定在代碼中加入調(diào)試信息的多少。默認(rèn)的級(jí)別是2(-g2),此時(shí)產(chǎn)生的調(diào)試信息包括擴(kuò)展的符號(hào)表、行號(hào)、局部或外部變量信息。級(jí)別3(-g3)包含級(jí)別2中的所有調(diào)試信息,以及源代碼中定義的宏。級(jí)別1(-g1)不包含局部變量和與行號(hào)有關(guān)的調(diào)試信息,因此只能夠用于回溯跟蹤和堆棧轉(zhuǎn)儲(chǔ)之用。回溯跟蹤指的是監(jiān)視程序在運(yùn)行過(guò)程中的函數(shù)調(diào)用歷史,堆棧轉(zhuǎn)儲(chǔ)則是一種以原始的十六進(jìn)制格式保存程序執(zhí)行環(huán)境的方法,兩者都是經(jīng)常用到的調(diào)試手段。

GCC產(chǎn)生的調(diào)試符號(hào)具有普遍的適應(yīng)性,可以被許多調(diào)試器加以利用,但如果使用的是GDB,那么還可以通過(guò)-ggdb選項(xiàng)在生成的二進(jìn)制代碼中包含GDB專(zhuān)用的調(diào)試信息。這種做法的優(yōu)點(diǎn)是可以方便GDB的調(diào)試工作,但缺點(diǎn)是可能導(dǎo)致其它調(diào)試器(如DBX)無(wú)法進(jìn)行正常的調(diào)試。選項(xiàng)-ggdb能夠接受的調(diào)試級(jí)別和-g是完全一樣的,它們對(duì)輸出的調(diào)試符號(hào)有著相同的影響。

需要注意的是,使用任何一個(gè)調(diào)試選項(xiàng)都會(huì)使最終生成的二進(jìn)制文件的大小急劇增加,同時(shí)增加程序在執(zhí)行時(shí)的開(kāi)銷(xiāo),因此調(diào)試選項(xiàng)通常僅在軟件的開(kāi)發(fā)和調(diào)試階段使用。調(diào)試選項(xiàng)對(duì)生成代碼大小的影響從下面的對(duì)比過(guò)程中可以看出來(lái):

# gcc optimize.c -o optimize

# ls optimize -l-rwxrwxr-x  1 xiaowp   xiaowp  11649 Nov 20 08:53 optimize  (未加調(diào)試選項(xiàng))

# gcc -g optimize.c -o optimize

# ls optimize -l-rwxrwxr-x  1 xiaowp   xiaowp  15889 Nov 20 08:54 optimize  (加入調(diào)試選項(xiàng))

雖然調(diào)試選項(xiàng)會(huì)增加文件的大小,但事實(shí)上Linux中的許多軟件在測(cè)試版本甚至最終發(fā)行版本中仍然使用了調(diào)試選項(xiàng)來(lái)進(jìn)行編譯,這樣做的目的是鼓勵(lì)用戶(hù)在發(fā)現(xiàn)問(wèn)題時(shí)自己動(dòng)手解決,是Linux的一個(gè)顯著特色。

下面還是通過(guò)一個(gè)具體的實(shí)例說(shuō)明如何利用調(diào)試符號(hào)來(lái)分析錯(cuò)誤,所用程序見(jiàn)清單4所示。

清單4:crash.c

#include <stdio.h>

 int main(void)

{  

int input =0;  

printf("Input an integer:");  

scanf("%d", input);  

printf("The integer you input is %dn", input); 

 return 0;

}

編譯并運(yùn)行上述代碼,會(huì)產(chǎn)生一個(gè)嚴(yán)重的段錯(cuò)誤(Segmentation fault)如下:

# gcc -g crash.c -o crash

# ./crashInput

an integer:10Segmentation fault

為了更快速地發(fā)現(xiàn)錯(cuò)誤所在,可以使用GDB進(jìn)行跟蹤調(diào)試,方法如下:

# gdb crashGNU gdb Red Hat Linux (5.3post-0.20021129.18rh)……(gdb)

當(dāng)GDB提示符出現(xiàn)的時(shí)候,表明GDB已經(jīng)做好準(zhǔn)備進(jìn)行調(diào)試了,現(xiàn)在可以通過(guò)run命令讓程序開(kāi)始在GDB的監(jiān)控下運(yùn)行:

(gdb) runStarting program: /home/xiaowp/thesis/gcc/code/crashInput an integer:10Program received signal SIGSEGV, Segmentation fault.0x4008576b in _IO_vfscanf_internal () from /lib/libc.so.6

仔細(xì)分析一下GDB給出的輸出結(jié)果不難看出,程序是由于段錯(cuò)誤而導(dǎo)致異常中止的,說(shuō)明內(nèi)存操作出了問(wèn)題,具體發(fā)生問(wèn)題的地方是在調(diào)用 _IO_vfscanf_internal ( )的時(shí)候。為了得到更加有價(jià)值的信息,可以使用GDB提供的回溯跟蹤命令backtrace,執(zhí)行結(jié)果如下:

(gdb) backtrace

#0  0x4008576b in _IO_vfscanf_internal () from /lib/libc.so.6

#1  0xbffff0c0 in ?? ()

#2  0x4008e0ba in scanf () from /lib/libc.so.6

#3  0x08048393 in main () at crash.c:11

#4  0x40042917 in __libc_start_main () from /lib/libc.so.6

跳過(guò)輸出結(jié)果中的前面三行,從輸出結(jié)果的第四行中不難看出,GDB已經(jīng)將錯(cuò)誤定位到crash.c中的第11行了。現(xiàn)在仔細(xì)檢查一下:

(gdb) frame 3

#3  0x08048393 in main () at crash.c:1111       scanf("%d", input);

使用GDB提供的frame命令可以定位到發(fā)生錯(cuò)誤的代碼段,該命令后面跟著的數(shù)值可以在backtrace命令輸出結(jié)果中的行首找到。現(xiàn)在已經(jīng)發(fā)現(xiàn)錯(cuò)誤所在了,應(yīng)該將

scanf("%d", input);改為scanf("%d", &input);

完成后就可以退出GDB了,命令如下:

(gdb) quit

GDB的功能遠(yuǎn)遠(yuǎn)不止如此,它還可以單步跟蹤程序、檢查內(nèi)存變量和設(shè)置斷點(diǎn)等。

調(diào)試時(shí)可能會(huì)需要用到編譯器產(chǎn)生的中間結(jié)果,這時(shí)可以使用-save-temps選項(xiàng),讓GCC將預(yù)處理代碼、匯編代碼和目標(biāo)代碼都作為文件保存起來(lái)。如果想檢查生成的代碼是否能夠通過(guò)手工調(diào)整的辦法來(lái)提高執(zhí)行性能,在編譯過(guò)程中生成的中間文件將會(huì)很有幫助,具體情況如下:

# gcc -save-temps foo.c -o foo

# ls foo*foo  foo.c  foo.i  foo.s

GCC 支持的其它調(diào)試選項(xiàng)還包括-p和-pg,它們會(huì)將剖析(Profiling)信息加入到最終生成的二進(jìn)制代碼中。剖析信息對(duì)于找出程序的性能瓶頸很有幫助,是協(xié)助Linux程序員開(kāi)發(fā)出高性能程序的有力工具。在編譯時(shí)加入-p選項(xiàng)會(huì)在生成的代碼中加入通用剖析工具(Prof)能夠識(shí)別的統(tǒng)計(jì)信息,而- pg選項(xiàng)則生成只有GNU剖析工具(Gprof)才能識(shí)別的統(tǒng)計(jì)信息。

最后提醒一點(diǎn),雖然GCC允許在優(yōu)化的同時(shí)加入調(diào)試符號(hào)信息,但優(yōu)化后的代碼對(duì)于調(diào)試本身而言將是一個(gè)很大的挑戰(zhàn)。代碼在經(jīng)過(guò)優(yōu)化之后,在源程序中聲明和使用的變量很可能不再使用,控制流也可能會(huì)突然跳轉(zhuǎn)到意外的地方,循環(huán)語(yǔ)句有可能因?yàn)檠h(huán)展開(kāi)而變得到處都有,所有這些對(duì)調(diào)試來(lái)講都將是一場(chǎng)噩夢(mèng)。建議在調(diào)試的時(shí)候最好不使用任何優(yōu)化選項(xiàng),只有當(dāng)程序在最終發(fā)行的時(shí)候才考慮對(duì)其進(jìn)行優(yōu)化。
上次的培訓(xùn)園地中介紹了GCC的編譯過(guò)程、警告提示功能、庫(kù)依賴(lài)、代碼優(yōu)化和程序調(diào)試六個(gè)方面的內(nèi)容。這期是最后的一部分內(nèi)容。
在將源代碼變成可執(zhí)行文件的過(guò)程中,需要經(jīng)過(guò)許多中間步驟,包含預(yù)處理、編譯、匯編和連接。這些過(guò)程實(shí)際上是由不同的程序負(fù)責(zé)完成的。大多數(shù)情況下GCC可以為L(zhǎng)inux程序員完成所有的后臺(tái)工作,自動(dòng)調(diào)用相應(yīng)程序進(jìn)行處理。

這樣做有一個(gè)很明顯的缺點(diǎn),就是GCC在處理每一個(gè)源文件時(shí),最終都需要生成好幾個(gè)臨時(shí)文件才能完成相應(yīng)的工作,從而無(wú)形中導(dǎo)致處理速度變慢。例如,GCC 在處理一個(gè)源文件時(shí),可能需要一個(gè)臨時(shí)文件來(lái)保存預(yù)處理的輸出、一個(gè)臨時(shí)文件來(lái)保存編譯器的輸出、一個(gè)臨時(shí)文件來(lái)保存匯編器的輸出,而讀寫(xiě)這些臨時(shí)文件顯然需要耗費(fèi)一定的時(shí)間。當(dāng)軟件項(xiàng)目變得非常龐大的時(shí)候,花費(fèi)在這上面的代價(jià)可能會(huì)變得很沉重。

解決的辦法是,使用Linux提供的一種更加高效的通信方式—管道。它可以用來(lái)同時(shí)連接兩個(gè)程序,其中一個(gè)程序的輸出將被直接作為另一個(gè)程序的輸入,這樣就可以避免使用臨時(shí)文件,但編譯時(shí)卻需要消耗更多的內(nèi)存。

在編譯過(guò)程中使用管道是由GCC的-pipe選項(xiàng)決定的。下面的這條命令就是借助GCC的管道功能來(lái)提高編譯速度的:

# gcc -pipe foo.c -o foo

在編譯小型工程時(shí)使用管道,編譯時(shí)間上的差異可能還不是很明顯,但在源代碼非常多的大型工程中,差異將變得非常明顯。

文件擴(kuò)展名

在使用GCC的過(guò)程中,用戶(hù)對(duì)一些常用的擴(kuò)展名一定要熟悉,并知道其含義。為了方便大家學(xué)習(xí)使用GCC,在此將這些擴(kuò)展名羅列如下:

.c C原始程序;

.C C++原始程序;

.cc C++原始程序;

.cxx C++原始程序;

.m Objective-C原始程序;

.i 已經(jīng)過(guò)預(yù)處理的C原始程序;

.ii 已經(jīng)過(guò)預(yù)處理之C++原始程序;

.s 組合語(yǔ)言原始程序;

.S 組合語(yǔ)言原始程序;

.h 預(yù)處理文件(標(biāo)頭文件);

.o 目標(biāo)文件;

.a 存檔文件。

GCC常用選項(xiàng)

GCC作為L(zhǎng)inux下C/C++重要的編譯環(huán)境,功能強(qiáng)大,編譯選項(xiàng)繁多。為了方便大家日后編譯方便,在此將常用的選項(xiàng)及說(shuō)明羅列出來(lái)如下:

-c 通知GCC取消鏈接步驟,即編譯源碼并在最后生成目標(biāo)文件;

-Dmacro 定義指定的宏,使它能夠通過(guò)源碼中的#ifdef進(jìn)行檢驗(yàn);

-E 不經(jīng)過(guò)編譯預(yù)處理程序的輸出而輸送至標(biāo)準(zhǔn)輸出;

-g3 獲得有關(guān)調(diào)試程序的詳細(xì)信息,它不能與-o選項(xiàng)聯(lián)合使用;

-Idirectory 在包含文件搜索路徑的起點(diǎn)處添加指定目錄;

-llibrary 提示鏈接程序在創(chuàng)建最終可執(zhí)行文件時(shí)包含指定的庫(kù);

-O、-O2、-O3 將優(yōu)化狀態(tài)打開(kāi),該選項(xiàng)不能與-g選項(xiàng)聯(lián)合使用;

-S 要求編譯程序生成來(lái)自源代碼的匯編程序輸出;

-v 啟動(dòng)所有警報(bào);

-Wall 在發(fā)生警報(bào)時(shí)取消編譯操作,即將警報(bào)看作是錯(cuò)誤;

-Werror 在發(fā)生警報(bào)時(shí)取消編譯操作,即把報(bào)警當(dāng)作是錯(cuò)誤;

-w 禁止所有的報(bào)警。

小結(jié)

GCC 是在Linux下開(kāi)發(fā)程序時(shí)必須掌握的工具之一。本文對(duì)GCC做了一個(gè)簡(jiǎn)要的介紹,主要講述了如何使用GCC編譯程序、產(chǎn)生警告信息、調(diào)試程序和加快 GCC的編譯速度。對(duì)所有希望早日跨入Linux開(kāi)發(fā)者行列的人來(lái)說(shuō),GCC就是成為一名優(yōu)秀的Linux程序員的起跑線。


 
Copyright © 笑笑生 Powered by: 博客園 模板提供:滬江博客
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久精品九九| 国产美女扒开尿口久久久| 国产综合久久| 欧美激情一区二区三区在线视频观看 | 欧美日韩国产区| 亚洲永久在线观看| 欧美一区二区黄| 夜夜爽夜夜爽精品视频| 亚洲欧美卡通另类91av| 91久久精品国产91久久性色tv| 日韩午夜视频在线观看| 韩日精品视频| 亚洲色图自拍| 亚洲国产精品一区二区第四页av | 伊人一区二区三区久久精品| 亚洲永久精品大片| 欧美日本亚洲视频| 国产精品99久久久久久白浆小说| 日韩视频一区二区三区在线播放免费观看 | 亚洲精品综合| 狠狠色2019综合网| 在线一区二区三区四区| 在线视频观看日韩| 亚洲一区欧美| 亚洲午夜高清视频| 美女999久久久精品视频| 欧美在线观看你懂的| 欧美日韩精品免费在线观看视频| 久久综合伊人77777| 国产精品入口麻豆原神| 亚洲人成亚洲人成在线观看| 国产一区二区三区黄视频| 中日韩午夜理伦电影免费| 亚洲精品一二| 久久亚洲影院| 久久久欧美精品sm网站| 国产精品视频免费观看www| 亚洲乱码久久| 亚洲免费播放| 欧美激情综合色综合啪啪| 欧美r片在线| 亚洲男人的天堂在线| 在线性视频日韩欧美| 免费在线亚洲欧美| 农村妇女精品| 在线日韩精品视频| 久久久精品国产免费观看同学| 午夜亚洲精品| 欧美在线三区| 国产精品日韩电影| 亚洲影院在线观看| 午夜精品久久久久久久蜜桃app | 亚洲欧美激情诱惑| 欧美午夜激情小视频| 亚洲免费观看在线视频| 99国产精品久久久久久久成人热| 欧美国产日韩a欧美在线观看| 欧美激情精品久久久久久黑人 | 亚洲精品韩国| 亚洲最新在线视频| 欧美日韩免费精品| 亚洲一区在线观看视频 | 欧美91视频| 亚洲国产精品美女| 亚洲狼人精品一区二区三区| 欧美激情一区二区| 亚洲精品美女久久7777777| 日韩午夜在线观看视频| 欧美午夜在线视频| 小处雏高清一区二区三区| 久久久久久久一区二区三区| 亚洲成人在线| 欧美日本免费一区二区三区| 在线视频欧美日韩| 久久精品综合| 亚洲人成高清| 国产精品久久久久久亚洲调教 | 久久久久久精| 亚洲欧美精品suv| 亚洲视频免费看| 欧美一区二区三区免费在线看| 老司机午夜精品视频| 欧美日韩在线免费观看| 久久aⅴ国产欧美74aaa| 欧美精品激情在线| 99成人在线| 欧美国产极速在线| 久久久久国色av免费看影院| 国产欧美日韩一区二区三区| 欧美一区二区三区精品| 亚洲影院在线| 激情欧美一区二区三区| 国产精品亚洲产品| 亚洲女人av| 香蕉成人伊视频在线观看| 国产精品一区二区久久久| 久久九九国产精品怡红院| 亚洲福利专区| 亚洲韩日在线| 欧美专区福利在线| 国产精品综合久久久| 亚洲人成网站在线观看播放| 久久精品视频一| 亚洲欧美日韩专区| 国产精品久久久久久妇女6080| 日韩一区二区精品在线观看| 欧美在线视频观看免费网站| 久久精品首页| 狠狠网亚洲精品| 亚洲二区在线| 久久国产精品毛片| 亚洲美洲欧洲综合国产一区| 久久久青草青青国产亚洲免观| 国产精品一区久久| 久久乐国产精品| 欧美在线观看一区| 国产视频一区在线观看| 老司机aⅴ在线精品导航| 亚欧成人精品| 性欧美video另类hd性玩具| 欧美日韩国产高清| 久久精品成人| 一本色道久久综合亚洲二区三区| 美女图片一区二区| 久久精品亚洲热| 亚洲女同精品视频| 日韩一级免费| 91久久黄色| 亚洲福利视频专区| 雨宫琴音一区二区在线| 国产主播一区二区| 国产欧美日韩亚州综合| 欧美日韩一区二区在线视频 | 国产精品一区二区欧美| 欧美日韩国产综合一区二区| 牛牛精品成人免费视频| 久久一二三四| 久久一区亚洲| 久久免费少妇高潮久久精品99| 午夜一区在线| 午夜精品福利在线| 午夜亚洲福利在线老司机| 亚洲一区二区三区免费观看| 亚洲九九精品| 99热免费精品在线观看| 日韩一级网站| 在线视频欧美日韩精品| 亚洲夜晚福利在线观看| 欧美三级资源在线| 亚洲视频日本| 亚洲天堂av图片| 亚洲免费av片| 亚洲天堂网在线观看| 一本不卡影院| 亚洲综合日韩中文字幕v在线| 欧美日韩精品免费观看| 毛片精品免费在线观看| 午夜精品久久久久久久蜜桃app | 欧美在线观看天堂一区二区三区| 亚洲午夜精品福利| 欧美激情精品久久久久久蜜臀 | 欧美伊人久久大香线蕉综合69| 欧美一区二区三区免费视| 久久国产福利国产秒拍| 久久人人九九| 亚洲国产日韩一区二区| 亚洲国语精品自产拍在线观看| 日韩视频一区二区三区在线播放免费观看 | 欧美在线视频a| 久久国产精品久久w女人spa| 久久永久免费| 欧美日韩国内自拍| 国产女精品视频网站免费| 黄色亚洲免费| 一区二区三区国产精华| 欧美亚洲色图校园春色| 狂野欧美激情性xxxx| 亚洲精品国产无天堂网2021| 亚洲综合不卡| 欧美成人官网二区| 国产精品一区二区久激情瑜伽| 亚洲第一色中文字幕| 亚洲淫性视频| 欧美国产一区二区| 亚洲一级黄色| 免费日韩精品中文字幕视频在线| 欧美视频你懂的| 亚洲大片一区二区三区| 午夜视频久久久| 亚洲精品乱码久久久久久黑人 | 亚洲少妇在线| 男人的天堂亚洲在线| 99视频有精品| 欧美sm极限捆绑bd| 国产伦精品一区二区| 日韩网站在线观看| 久久尤物电影视频在线观看| 一本色道久久综合亚洲精品婷婷 | 国产精品系列在线播放| 亚洲欧洲视频|