• <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>

            為生存而奔跑

               :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
              271 Posts :: 0 Stories :: 58 Comments :: 0 Trackbacks

            留言簿(5)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            積分與排名

            • 積分 - 326966
            • 排名 - 74

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

             The History of GCC

            --------------------------------------------------------------------------------

              1984年,Richard Stallman發(fā)起了自由軟件運(yùn)動(dòng),GNU (Gnu's Not Unix)項(xiàng)目應(yīng)運(yùn)而生,3年后,最初版的GCC橫空出世,成為第一款可移植、可優(yōu)化、支持ANSI C的開(kāi)源C編譯器。

              GCC最初的全名是GNU C Compiler,之后,隨著GCC支持的語(yǔ)言越來(lái)越多,它的名稱(chēng)變成了GNU Compiler Collection。

              這里介紹的gcc是GCC的前端,C編譯器.

              警告信息

            --------------------------------------------------------------------------------

              -Wall : 顯示所有常用的編譯警告信息。

              -W    : 顯示更多的常用編譯警告,如:變量未使用、一些邏輯錯(cuò)誤。

              -Wconversion : 警告隱式類(lèi)型轉(zhuǎn)換。

              -Wshadow : 警告影子變量(在代碼塊中再次聲明已聲明的變量)

              -Wcast-qual :警告指針修改了變量的修飾符。如:指針修改const變量。

              -Wwrite-strings : 警告修改const字符串。

              -Wtraditional : 警告ANSI編譯器與傳統(tǒng)C編譯器有不同的解釋。

              -Werror : 即使只有警告信息,也不編譯。(gcc默認(rèn):若只有警告信息,則進(jìn)行編譯,若有錯(cuò)誤信息,則不編譯)

              C語(yǔ)言標(biāo)準(zhǔn)

            --------------------------------------------------------------------------------

              你可以在gcc的命令行中通過(guò)指定選項(xiàng)來(lái)選擇相應(yīng)的C語(yǔ)言標(biāo)準(zhǔn): 從傳統(tǒng)c到最新的GNU擴(kuò)展C. 默認(rèn)情況下, gcc使用最新的GNU C擴(kuò)展.

              -ansi : 關(guān)閉GNU擴(kuò)展中與ANSI C相抵觸的部分。

              -pedantic          : 關(guān)閉所有的GNU擴(kuò)展。

              -std=c89           : 遵循C89標(biāo)準(zhǔn)

              -std=c99           : 遵循C99標(biāo)準(zhǔn)

              -std=traditional : 使用原始C

              注意:后4個(gè)選項(xiàng)可以與-ansi結(jié)合使用,也可以單獨(dú)使用。

              可在gcc中使用大量GNU C擴(kuò)展.

              生成特定格式的文件

            --------------------------------------------------------------------------------

              以hello.c為例子,可以設(shè)置選項(xiàng)生成hello.i, hello.s, hello.o以及最終的hello文件:

              hello.c : 最初的源代碼文件;

              hello.i : 經(jīng)過(guò)編譯預(yù)處理的源代碼;

              hello.s : 匯編處理后的匯編代碼;

              hello.o : 編譯后的目標(biāo)文件,即含有最終編譯出的機(jī)器碼,但它里面所引用的其他文件中函數(shù)的內(nèi)存位置尚未定義。

              hello / a.out : 最終的可執(zhí)行文件

              (還有.a(靜態(tài)庫(kù)文件), .so(動(dòng)態(tài)庫(kù)文件), .s(匯編源文件)留待以后討論)

              如果你不通過(guò)-o指定生成可執(zhí)行文件名,那么會(huì)默認(rèn)生成a.out. 不指定生成文件名肯能覆蓋你上次生成的a.out.

              e.g.

              $ gcc hello.c

              在不給gcc傳遞任何參數(shù)的情況下, gcc執(zhí)行默認(rèn)的操作: 將源文件編譯為目標(biāo)文件--> 將目標(biāo)文件連接為可執(zhí)行文件(名為a.out) --> 刪除目標(biāo)文件.

              -c生成.o文件時(shí),默認(rèn)生成與源代碼的主干同名的.o文件。比如對(duì)應(yīng)hello.c生成hello.o. 但也可在生成目標(biāo)文件時(shí)指定目標(biāo)文件名(注意同時(shí)要給出.o后綴): $ gcc -c -o demo.o demo.c

              $ gcc -Wall -c hello.c              : 生成hello.o

              $ gcc -Wall -c -save-temps hello.c : 生成hello.i, hello.s, hello.o

              注意-Wall 選項(xiàng)的使用場(chǎng)合:僅在涉及到編譯(即會(huì)生成.o文件時(shí),用-Wall)

              多文件編譯、連接

            --------------------------------------------------------------------------------

              如果原文件分布于多個(gè)文件中:file1.c, file2,c

              $ gcc -Wall file1.c file2.c -o name

              若對(duì)其中一個(gè)文件作了修改,則可只重新編譯該文件,再連接所有文件:

              $ gcc -Wall -c file2.c

              $ gcc file1.c file2.o -c name

              注意:若編譯器在命令行中從左向右順序讀取.o文件,則它們的出現(xiàn)順序有限制:含有某函數(shù)定義的文件必須出現(xiàn)在含有調(diào)用該函數(shù)的文件之后。好在 GCC無(wú)此限制。

              編譯預(yù)處理

            --------------------------------------------------------------------------------

              以上述的hello.c為例, 要對(duì)它進(jìn)行編譯預(yù)備處理, 有兩種方法: 在gcc中指定-E選項(xiàng), 或直接調(diào)用cpp.gcc的編譯預(yù)處理命令程序?yàn)閏pp,比較新版本的gcc已經(jīng)將cpp集成了,但仍提供了cpp命令. 可以直接調(diào)用cpp命令, 也可以在gcc中指定-E選項(xiàng)指定它只進(jìn)行編譯預(yù)處理.

              $ gcc -E hello.c                            == $ cpp hello.c

              上述命令馬上將預(yù)處理結(jié)果顯示出來(lái). 不利于觀看. 可采用-c將預(yù)處理結(jié)果保存:

              $ gcc -E -c hello.i hello.c              == $ cpp -o hello.i hello.c

              注意, -c指定名稱(chēng)要給出".i"后綴.

              另外, gcc針對(duì)編譯預(yù)處理提供了一些選項(xiàng):

              (1) 除了直接在源代碼中用 #define NAME來(lái)定義宏外,gcc可在命令行中定義宏:-DNAME(其中NAME為宏名), 也可對(duì)宏賦值: -DNAME=value 注意等號(hào)兩邊不能有空格! 由于宏擴(kuò)展只是一個(gè)替換過(guò)程,也可以將value換成表達(dá)式,但要在兩邊加上雙括號(hào): -DNAME="statement"

              e.g. $ gcc -Wall -DVALUE="2+2" tmp.c -o tmp

              如果不顯示地賦值,如上例子,只給出:-DVALUE,gcc將使用默認(rèn)值:1.

              (2) 除了用戶(hù)定義的宏外, 有一些宏是編譯器自動(dòng)定義的,它們以__開(kāi)頭,運(yùn)行: $ cpp -dM /dev/null, 可以看到這些宏. 注意, 其中含有不以__開(kāi)頭的非ANSI宏,它們可以通過(guò)-ansi選項(xiàng)被禁止。

              查看宏擴(kuò)展

              1, 運(yùn)行 $ gcc -E test.c ,gcc對(duì)test.c進(jìn)行編譯預(yù)處理,并立馬顯示結(jié)果. (不執(zhí)行編譯) 2, 運(yùn)行 $ gcc -c -save-temps test.c ,不光產(chǎn)生test.o,還產(chǎn)生test.i, test.s,前者是編譯預(yù)處理結(jié)果, 后者是匯編結(jié)果.

              利用Emacs查看編譯預(yù)處理結(jié)果

              針對(duì)含有編譯預(yù)處理命令的代碼,可以利用emacs方便地查看預(yù)處理結(jié)果,而不需執(zhí)行編譯,更為方便的是,可以只選取一段代碼,而非整個(gè)文件:

              1,選擇想要查看的代碼

              2,C-c C-e (M-x c-macro-expand)

              這樣,就自動(dòng)在一個(gè)名為"Macroexpansion"的buffer中顯示pre-processed結(jié)果.

              生成匯編代碼

            --------------------------------------------------------------------------------

              使用"-S"選項(xiàng)指定gcc生成以".s"為后綴的匯編代碼:

              $ gcc -S hello.c

              $ gcc -S -o hello.s hello.c

              生成匯編語(yǔ)言的格式取決于目標(biāo)平臺(tái). 另外, 如果是多個(gè).c文件, 那么針對(duì)每一個(gè).c文件生成一個(gè).s文件.


             包含頭文件 在程序中包含與連接庫(kù)對(duì)應(yīng)的頭文件是很重要的方面,要使用庫(kù),就一定要能正確地引用頭文件。一般在代碼中通過(guò)#include引入頭文件, 如果頭文件位于系統(tǒng)默認(rèn)的包含路徑(/usr/includes), 則只需在#include中給出頭文件的名字, 不需指定完整路徑. 但若要包含的頭文件位于系統(tǒng)默認(rèn)包含路徑之外, 則有其它的工作要做: 可以(在源文件中)同時(shí)指定頭文件的全路徑. 但考慮到可移植性,最好通過(guò)-I在調(diào)用gcc的編譯命令中指定。

              下面看這個(gè)求立方的小程序(陰影語(yǔ)句表示剛開(kāi)始不存在):

              #include <stdio.h>

              #include <math.h>

              int main(int argc, char *argv[])

              {

              double x = pow (2.0, 3.0);

              printf("The cube of 2.0 is %f\n", x);

              return 0;

              }

              使用gcc-2.95來(lái)編譯它(-lm選項(xiàng)在后面的連接選項(xiàng)中有介紹, 這里只討論頭文件的包含問(wèn)題):

              $ gcc-2.95 -Wall pow.c -lm -o pow_2.95

              pow.c: In function `main':

              pow.c:5: warning: implicit declaration of function `pow'

              程序編譯成功,但gcc給出警告: pow函數(shù)隱式聲明。

              $ ./pow_2.95

              The cube of 2.0 is 1.000000

              明顯執(zhí)行結(jié)果是錯(cuò)誤的,在源程序中引入頭文件(#include <math.h>),消除了錯(cuò)誤。

              不要忽略Warning信息!它可能預(yù)示著,程序雖然編譯成功,但運(yùn)行結(jié)果可能有錯(cuò)。故,起碼加上"-Wall"編譯選項(xiàng)!并盡量修正 Warning警告。

              搜索路徑

              首先要理解 #include<file.h>和#include"file.h"的區(qū)別:

              #include<file.h>只在默認(rèn)的系統(tǒng)包含路徑搜索頭文件

              #include"file.h"首先在當(dāng)前目錄搜索頭文件, 若頭文件不位于當(dāng)前目錄, 則到系統(tǒng)默認(rèn)的包含路徑搜索頭文件.

              UNIX類(lèi)系統(tǒng)默認(rèn)的系統(tǒng)路徑為:

              頭文件,包含路徑: /usr/local/include/ or /usr/include/

              庫(kù)文件,連接路徑: /usr/local/lib/          or /usr/lib/

              對(duì)于標(biāo)準(zhǔn)c庫(kù)(glibc或其它c(diǎn)庫(kù))的頭文件, 我們可以直接在源文件中使用#include <file.h>來(lái)引入頭文件.

              如果要在源文件中引入自己的頭文件, 就需要考慮下面的問(wèn)題:

              1, 如果使用非系統(tǒng)頭文件, 頭文件和源文件位于同一個(gè)目錄, 如何引用頭文件呢?

              ——我們可以簡(jiǎn)單地在源文件中使用 #include "file.h", gcc將當(dāng)前目錄的file.h引入到源文件. 如果你很固執(zhí), 仍想使用#include <file.h>語(yǔ)句, 可以在調(diào)用gcc時(shí)添加"-I."來(lái)將當(dāng)前目錄添加到系統(tǒng)包含路徑. 細(xì)心的朋友可能會(huì)想到: 這樣對(duì)引用其它頭文件會(huì)不會(huì)有影響? 比如, #include<file.h>之后緊接著一個(gè)#include<math.h>, 它能正確引入math.h嗎? 答案是: 沒(méi)有影響. 仍然能正確引用math.h. 我的理解是: "-I."將當(dāng)前目錄作為包含路徑的第一選擇, 若在當(dāng)前目錄找不到頭文件, 則在默認(rèn)路徑搜索頭文件. 這實(shí)際上和#include"file.h"是一個(gè)意思.

              2, 對(duì)于比較大型的工程, 會(huì)有許多用戶(hù)自定義的頭文件, 并且頭文件和.c文件會(huì)位于不同的目錄. 又該如何在.c文件中引用頭文件呢?

              —— 可以直接在.c文件中利用#include“/path/file.h", 通過(guò)指定頭文件的路徑(可以是絕對(duì)路徑, 也可以是相對(duì)路徑)來(lái)包含頭文件. 但這明顯降低了程序的可移植性. 在別的系統(tǒng)環(huán)境下編譯可能會(huì)出現(xiàn)問(wèn)題. 所以還是利用"-I"選項(xiàng)指定頭文件完整的包含路徑.

              針對(duì)頭文件比較多的情況, 最好把它們統(tǒng)一放在一個(gè)目錄中, 比如~/project/include. 這樣就不需為不同的頭文件指定不同的路徑. 如果你嫌每次輸入這么多選項(xiàng)太麻煩, 你可以通過(guò)設(shè)置環(huán)境變量來(lái)添加路徑:

              $ C_INCLUDE_PATH=/opt/gdbm-1.8.3/include

              $ export C_INCLUDE_PATH

              $ LIBRART_PATH=/opt/gdbm-1.8.3/lib

              $ export LIBRART_PATH

              可一次指定多個(gè)搜索路徑,":"用于分隔它們,"."表示當(dāng)前路徑,如:

              $ C_INCLUDE_PATH=.:/opt/gdbm-1.8.3/include:/net/include

              $ LIBRARY_PATH=.:/opt/gdbm-1.8.3/lib:/net/lib

              (可以添加多個(gè)路徑,路徑之間用:相隔,.代表當(dāng)前目錄,若.在最前頭,也可省略)

              當(dāng)然,若想永久地添加這些路徑,可以在.bash_profile中添加上述語(yǔ)句.

              3, 還有一個(gè)比較猥瑣的辦法: 系統(tǒng)默認(rèn)的包含路徑不是/usr/include或/usr/local/include么? 我把自己的頭文件拷貝到其中的一個(gè)目錄, 不就可以了么? 的確可以這樣, 如果你只想在你自己的機(jī)器上編譯運(yùn)行這個(gè)程序的話(huà)

              前面介紹了三種添加搜索路徑的方法,如果這三種方法一起使用,優(yōu)先級(jí)如何呢?

              命令行設(shè)置 > 環(huán)境變量設(shè)置 > 系統(tǒng)默認(rèn)

              與外部庫(kù)連接

            --------------------------------------------------------------------------------

              前面介紹了如何包含頭文件. 而頭文件和庫(kù)是息息相關(guān)的, 使用庫(kù)時(shí), 要在源代碼中包含適當(dāng)?shù)念^文件,這樣才能聲明庫(kù)中函數(shù)的原型(發(fā)布庫(kù)時(shí), 就需要給出相應(yīng)的頭文件).

              和包含路徑一樣, 系統(tǒng)也有默認(rèn)的連接路徑:

              頭文件,包含路徑: /usr/local/include/ or /usr/include/

              庫(kù)文件,連接路徑: /usr/local/lib/          or /usr/lib/

              同樣地, 我們想要使用某個(gè)庫(kù)里的函數(shù), 必須將這個(gè)庫(kù)連接到使用那些函數(shù)的程序中.

              有一個(gè)例外: libc.a或libc.so (C標(biāo)準(zhǔn)庫(kù),它包含了ANSI C所定義的C函數(shù))是不需要你顯式連接的, 所有的C程序在運(yùn)行時(shí)都會(huì)自動(dòng)加載c標(biāo)準(zhǔn)庫(kù).

              除了C標(biāo)準(zhǔn)庫(kù)之外的庫(kù)稱(chēng)之為"外部庫(kù)", 它可能是別人提供給你的, 也可能是你自己創(chuàng)建的(后面有介紹如何創(chuàng)建庫(kù)的內(nèi)容).

              外部庫(kù)有兩種:(1)靜態(tài)連接庫(kù)lib.a

              (2)共享連接庫(kù)lib.so

              兩者的共同點(diǎn):

              .a, .so都是.o目標(biāo)文件的集合,這些目標(biāo)文件中含有一些函數(shù)的定義(機(jī)器碼),而這些函數(shù)將在連接時(shí)會(huì)被最終的可執(zhí)行文件用到。

              兩者的區(qū)別:

              靜態(tài)庫(kù).a : 當(dāng)程序與靜態(tài)庫(kù)連接時(shí),庫(kù)中目標(biāo)文件所含的所有將被程序使用的函數(shù)的機(jī)器碼被copy到最終的可執(zhí)行文件中. 靜態(tài)庫(kù)有個(gè)缺點(diǎn): 占用磁盤(pán)和內(nèi)存空間. 靜態(tài)庫(kù)會(huì)被添加到和它連接的每個(gè)程序中, 而且這些程序運(yùn)行時(shí), 都會(huì)被加載到內(nèi)存中. 無(wú)形中又多消耗了更多的內(nèi)存空間.

              共享庫(kù).so : 與共享庫(kù)連接的可執(zhí)行文件只包含它需要的函數(shù)的引用表,而不是所有的函數(shù)代碼,只有在程序執(zhí)行時(shí), 那些需要的函數(shù)代碼才被拷貝到內(nèi)存中, 這樣就使可執(zhí)行文件比較小, 節(jié)省磁盤(pán)空間(更進(jìn)一步,操作系統(tǒng)使用虛擬內(nèi)存,使得一份共享庫(kù)駐留在內(nèi)存中被多個(gè)程序使用).共享庫(kù)還有個(gè)優(yōu)點(diǎn): 若庫(kù)本身被更新, 不需要重新編譯與它連接的源程序。

              靜態(tài)庫(kù)

              下面我們來(lái)看一個(gè)簡(jiǎn)單的例子,計(jì)算2.0的平方根(假設(shè)文件名為sqrt.c):

              #include <math.h>

              #include <stdio.h>

              int

              main (void)

              {

              double x = sqrt (2.0);

              printf ("The square root of 2.0 is %f\n", x);

              return 0;

              }

              用gcc將它編譯為可執(zhí)行文件:

              $ gcc -Wall sqrt.c -o sqrt

              編譯成功,沒(méi)有任何警告或錯(cuò)誤信息。執(zhí)行結(jié)果也正確。

              $ ./sqrt

              The square root of 2.0 is 1.414214

              下面我們來(lái)看看剛才使用的gcc版本:

              $ gcc --version

              gcc (GCC) 4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)

              現(xiàn)在我用2.95版的gcc把sqrt.c再編譯一次:

              $ gcc-2.95 -Wall sqrt.c -o sqrt_2.95

              /tmp/ccVBJd2H.o: In function `main':

              sqrt.c:(.text+0x16): undefined reference to `sqrt'

              collect2: ld returned 1 exit status

              編譯器會(huì)給出上述錯(cuò)誤信息,這是因?yàn)閟qrt函數(shù)不能與外部數(shù)學(xué)庫(kù)"libm.a"相連。sqrt函數(shù)沒(méi)有在程序中定義,也不存在于默認(rèn)C庫(kù) "libc.a"中,如果用gcc-2.95,應(yīng)該顯式地選擇連接庫(kù)。上述出錯(cuò)信息中的"/tmp/ccVBJd2H.o"是gcc創(chuàng)造的臨時(shí)目標(biāo)文件, 用作連接時(shí)用。



            使用下列的命令可以成功編譯:

              $ gcc-2.95 -Wall sqrt.c /usr/lib/libm.a -o sqrt_2.95

              它告知gcc:在編譯sqrt.c時(shí),加入位于/usr/lib中的libm.a庫(kù)(C數(shù)學(xué)庫(kù))。

              C庫(kù)文件默認(rèn)位于/usr/lib, /usr/local/lib系統(tǒng)目錄中; gcc默認(rèn)地從/usr/local/lib, /usr/lib中搜索庫(kù)文件。(在我的Ubuntu系統(tǒng)中,C庫(kù)文件位于/urs/lib中。

              這里還要注意連接順序的問(wèn)題,比如上述命令,如果我改成:

              $ gcc-2.95 -Wall /usr/lib/libm.a sqrt.c -o sqrt_2.95

              gcc會(huì)給出出錯(cuò)信息:

              /tmp/cc6b3bIa.o: In function `main':

              sqrt.c:(.text+0x16): undefined reference to `sqrt'

              collect2: ld returned 1 exit status

              正如讀取目標(biāo)文件的順序,gcc也在命令行中從左向右讀取庫(kù)文件——任何包含某函數(shù)定義的庫(kù)文件必須位于調(diào)用該函數(shù)的目標(biāo)文件之后!

              指定庫(kù)文件的絕對(duì)路徑比較繁瑣,有一種簡(jiǎn)化方法,相對(duì)于上述命令,可以用下面的命令來(lái)替代:

              $ gcc-2.95 -Wall sqrt.c -lm -o sqrt_2.95

              其中的"-l"表示與庫(kù)文件連接,"m"代表"libm.a"中的m。一般而言,"-lNAME"選項(xiàng)會(huì)使gcc將目標(biāo)文件與名 為"libNAME.a"的庫(kù)文件相連。(這里假設(shè)使用默認(rèn)目錄中的庫(kù),對(duì)于其他目錄中的庫(kù)文件,參考后面的“搜索路徑”。)

              上面所提到的"libm.a"就是靜態(tài)庫(kù)文件,所有靜態(tài)庫(kù)文件的擴(kuò)展名都是.a!

              $ whereis libm.a

              libm: /usr/lib/libm.a /usr/lib/libm.so

              正如前面所說(shuō),默認(rèn)的庫(kù)文件位于/usr/lib/或/usr/local/lib/目錄中。其中,libm.a是靜態(tài)庫(kù)文件,libm.so 是后面會(huì)介紹的動(dòng)態(tài)共享庫(kù)文件。

              如果調(diào)用的函數(shù)都包含在libc.a中(C標(biāo)準(zhǔn)庫(kù)被包含在/usr/lib/libc.a中,它包含了ANSI C所定義的C函數(shù))。那么沒(méi)有必要顯式指定libc.a:所有的C程序運(yùn)行時(shí)都自動(dòng)包含了C標(biāo)準(zhǔn)庫(kù)?。ㄔ囋?$ gcc-2.95 -Wall hello.c -o hello)。

              共享庫(kù)

              正因?yàn)楣蚕韼?kù)的優(yōu)點(diǎn),如果系統(tǒng)中存在.so庫(kù),gcc默認(rèn)使用共享庫(kù)(在/usr/lib/目錄中,庫(kù)文件以共享和靜態(tài)兩種版本存在)。

              運(yùn)行:$ gcc -Wall -L. hello.c -lNAME -o hello

              gcc先檢查是否有替代的libNAME.so庫(kù)可用。

              正如前面所說(shuō),共享庫(kù)以.so為擴(kuò)展名(so == shared object)。

              那么,如果不想用共享庫(kù),而只用靜態(tài)庫(kù)呢?可以加上 -static選項(xiàng)

              $ gcc -Wall -static hello.c -lNAME -o hello

              它等價(jià)于:

              $ gcc -Wall hello.c libNAME.a -o hello

              $ gcc-2.95 -Wall sqrt.c -static -lm -o sqrt_2.95_static

              $ gcc-2.95 -Wall sqrt.c -lm -o sqrt_2.95_default

              $ gcc-2.95 -Wall sqrt.c /usr/lib/libm.a -o sqrt_2.95_a

              $ gcc-2.95 -Wall sqrt.c /usr/lib/libm.so -o sqrt_2.95_so

              $ ls -l sqrt*

              -rwxr-xr-x 1 zp zp 21076 2006-04-25 14:52 sqrt_2.95_a

              -rwxr-xr-x 1 zp zp   7604 2006-04-25 14:52 sqrt_2.95_default

              -rwxr-xr-x 1 zp zp   7604 2006-04-25 14:52 sqrt_2.95_so

              -rwxr-xr-x 1 zp zp 487393 2006-04-25 14:52 sqrt_2.95_static

              上述用四種方式編譯sqrt.c,并比較了可執(zhí)行文件的大小。奇怪的是,-static -lm 和 /lib/libm.a為什么有區(qū)別?有知其原因著,懇請(qǐng)指明,在此謝謝了! :)

              如果libNAME.a在當(dāng)前目錄,應(yīng)執(zhí)行下面的命令:

              $ gcc -Wall -L. hello.c -lNAME -o hello

              -L.表示將當(dāng)前目錄加到連接路徑。

              利用GNU archiver創(chuàng)建庫(kù)

              $ ar cr libhello.a hello_fn.o by_fn.o

              從hello_fn.o和by_fn.o創(chuàng)建libihello.a,其中cr表示:creat & replace

              $ ar t libhello.a

              列出libhello.a中的內(nèi)容,t == table

             ?。ㄒ部蓜?chuàng)建libhello.so)

              關(guān)于創(chuàng)建庫(kù)的詳細(xì)介紹,可參考本blog的GNU binutils筆記

              調(diào)試

            --------------------------------------------------------------------------------

              一般地,可執(zhí)行文件中是不包含任何對(duì)源代碼的參考的,而debugger要工作,就要知道目標(biāo)文件/可執(zhí)行文件中的機(jī)器碼對(duì)應(yīng)的源代碼的信息 (如:哪條語(yǔ)句、函數(shù)名、變量名...). debugger工作原理:將函數(shù)名、變量名,對(duì)它們的引用,將所有這些對(duì)象對(duì)應(yīng)的代碼行號(hào)儲(chǔ)存到目標(biāo)文件或可執(zhí)行文件的符號(hào)表中。

              GCC提供-g選項(xiàng),將調(diào)試信息加入到目標(biāo)文件或可執(zhí)行文件中。

              $ gcc -Wall -g hello.c -o hello

              注意:若發(fā)生了段錯(cuò)誤,但沒(méi)有core dump,是由于系統(tǒng)禁止core文件的生成!

              $ ulimit -c  ,若顯示為0,則系統(tǒng)禁止了core dump

              解決方法:

              $ ulimit -c unlimited ?。ㄖ粚?duì)當(dāng)前shell進(jìn)程有效)

              或在~/.bashrc 的最后加入: ulimit -c unlimited (一勞永逸)

              優(yōu)化

            --------------------------------------------------------------------------------

              GCC具有優(yōu)化代碼的功能,代碼的優(yōu)化是一項(xiàng)比較復(fù)雜的工作,它可歸為:源代碼級(jí)優(yōu)化、速度與空間的權(quán)衡、執(zhí)行代碼的調(diào)度。

              GCC提供了下列優(yōu)化選項(xiàng):

              -O0 : 默認(rèn)不優(yōu)化(若要生成調(diào)試信息,最好不優(yōu)化)

              -O1 : 簡(jiǎn)單優(yōu)化,不進(jìn)行速度與空間的權(quán)衡優(yōu)化;

              -O2 : 進(jìn)一步的優(yōu)化,包括了調(diào)度。(若要優(yōu)化,該選項(xiàng)最適合,它是GNU發(fā)布軟件的默認(rèn)優(yōu)化級(jí)別;

              -O3 : 雞肋,興許使程序速度更慢;

              -funroll-loops : 展開(kāi)循環(huán),會(huì)使可執(zhí)行文件增大,而速度是否增加取決于特定環(huán)境;

              -Os : 生成最小執(zhí)行文件;

              一般來(lái)說(shuō),調(diào)試時(shí)不優(yōu)化,一般的優(yōu)化選項(xiàng)用-O2(gcc允許-g與-O2聯(lián)用,這也是GNU軟件包發(fā)布的默認(rèn)選項(xiàng)),embedded可以考 慮-Os。

              注意:此處為O?。ǚ?或小寫(xiě)的o,-o是指定可執(zhí)行文件名)。

              檢驗(yàn)優(yōu)化結(jié)果的方法:$ time ./prog

              time測(cè)量指定程序的執(zhí)行時(shí)間,結(jié)果由三部分組成:

              real : 進(jìn)程總的執(zhí)行時(shí)間, 它和系統(tǒng)負(fù)載有關(guān)(包括了進(jìn)程調(diào)度,切換的時(shí)間)

              user: 被測(cè)量進(jìn)程中用戶(hù)指令的執(zhí)行時(shí)間

              sys : 被測(cè)量進(jìn)程中內(nèi)核代用戶(hù)指令執(zhí)行的時(shí)間

              user和sys的和被稱(chēng)為CPU時(shí)間.

              注意:對(duì)代碼的優(yōu)化可能會(huì)引發(fā)警告信息,移出警告的辦法不是關(guān)閉優(yōu)化,而是調(diào)整代碼。

            posted on 2010-07-27 15:32 baby-fly 閱讀(692) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): Ubuntu&Linux
            久久久久久久久久久久中文字幕 | 国产精品久久久久无码av| 久久精品国产亚洲av影院| 久久久久免费视频| 久久综合久久综合九色| 亚洲人成精品久久久久| 武侠古典久久婷婷狼人伊人| 久久精品一区二区三区中文字幕| 99久久国产综合精品麻豆| 久久无码人妻一区二区三区| 国产伊人久久| 精品人妻伦九区久久AAA片69| 久久99国产综合精品女同| 无码8090精品久久一区| 国产香蕉97碰碰久久人人| 久久国产免费观看精品| 国产精品久久久久久福利漫画| 久久Av无码精品人妻系列| 少妇人妻88久久中文字幕| 亚洲日韩欧美一区久久久久我 | 久久综合狠狠综合久久综合88| 亚洲中文字幕无码久久2017| 青青热久久国产久精品| 久久久久无码精品国产不卡| 久久久久久久久无码精品亚洲日韩 | 久久国产三级无码一区二区| 国内精品久久久久久中文字幕| 国内精品久久国产大陆| 久久精品无码午夜福利理论片| 久久九九久精品国产免费直播| 99久久精品免费看国产一区二区三区| 久久亚洲欧美日本精品| 狠狠色噜噜色狠狠狠综合久久| 久久精品国产乱子伦| 日韩久久久久中文字幕人妻| 久久福利资源国产精品999| 77777亚洲午夜久久多喷| 精品久久久久久久无码 | 人妻少妇精品久久| 欧美无乱码久久久免费午夜一区二区三区中文字幕 | 久久亚洲高清综合|