<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > Linux操作系統中GCC的應用介紹(下)

Linux操作系統中GCC的應用介紹(下)

——
作者: 時(shí)間:2007-04-18 來(lái)源:電子產(chǎn)品世界 收藏

代碼優(yōu)化

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

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

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

清單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)化選項進(jìn)行編譯:

# gcc -Wall optimize.c -o optimize

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

# time ./optimize
Result is 400002019.000000
real 0m14.942s
user 0m14.940s
sys 0m0.000s

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

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

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

# time ./optimize
Result is 400002019.000000
real 0m3.256s
user 0m3.240s
sys 0m0.000s

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

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

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

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

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

調試

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

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

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

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

# gcc optimize.c -o optimize
# ls optimize -l
-rwxrwxr-x 1 xiaowp xiaowp 11649 Nov 20 08:53 optimize (未加調試選項)
# gcc -g optimize.c -o optimize
# ls optimize -l
-rwxrwxr-x 1 xiaowp xiaowp 15889 Nov 20 08:54 optimize (加入調試選項)

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

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

清單4:crash.c

#include 
int main(void)
{
int input =0;
printf("Input an integer:");
scanf("%d", input);
printf("The integer you input is %d\n", input);
return 0;
}

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

# gcc -g crash.c -o crash
# ./crash
Input an integer:10
Segmentation fault

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

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

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

(gdb) run
Starting program: /home/xiaowp/thesis/gcc/code/crash
Input an integer:10

Program received signal SIGSEGV, Segmentation fault.
0x4008576b in _IO_vfscanf_internal () from /lib/libc.so.6
{{分頁(yè)}}

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

(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ò)輸出結果中的前面三行,從輸出結果的第四行中不難看出,GDB已經(jīng)將錯誤定位到crash.c中的第11行了?,F在仔細檢查一下:

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


 

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

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

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

(gdb) quit

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

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

# gcc -save-temps foo.c -o foo
# ls foo*
foo foo.c foo.i foo.s

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

最后提醒一點(diǎn),雖然GCC允許在優(yōu)化的同時(shí)加入調試符號信息,但優(yōu)化后的代碼對于調試本身而言將是一個(gè)很大的挑戰。代碼在經(jīng)過(guò)優(yōu)化之后,在源程序中聲明和使用的變量很可能不再使用,控制流也可能會(huì )突然跳轉到意外的地方,循環(huán)語(yǔ)句有可能因為循環(huán)展開(kāi)而變得到處都有,所有這些對調試來(lái)講都將是一場(chǎng)噩夢(mèng)。建議在調試的時(shí)候最好不使用任何優(yōu)化選項,只有當程序在最終發(fā)行的時(shí)候才考慮對其進(jìn)行優(yōu)化。



 



評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>