gcc編譯器學習_第1頁
gcc編譯器學習_第2頁
gcc編譯器學習_第3頁
gcc編譯器學習_第4頁
gcc編譯器學習_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、gcc編譯器學習gcc and g+分別是gnu的c&c+編譯器gcc/g+在執(zhí)行編譯工作的時候,總共需要4步1.預處理,生成.i的文件預處理器cpp2.將預處理后的文件不轉換成匯編語言,生成文件.s編譯器egcs3.有匯編變?yōu)槟繕舜a(機器代碼)生成.o的文件匯編器as4.連接目標代碼,生成可執(zhí)行程序鏈接器ld開始.首先,我們應該知道如何調用編譯器。實際上,這很簡單。我們將從那個著名的第一個C程序開始。#include stdio.h int main()printf(Hello World!n);把這個文件保存為game.c。你可以在命令行下編譯它:gcc game.c在默認情況下,C編譯

2、器將生成一個名為a.out的可執(zhí)行文件。你可以鍵入如下命令運行它:a.out Hello World每一次編譯程序時,新的a.out將覆蓋原來的程序。你無法知道是哪個程序創(chuàng)建了a.out。我們可以通過使用-o編譯選項,告訴gcc我們想把可執(zhí)行文件叫什么名字。我們將把這個程序叫做game,我們可以使用任何名字,因為C沒有Java那樣的命名限制。gcc-o game game.c game Hello World到現(xiàn)在為止,我們離一個有用的程序還差得很遠。如果你覺得沮喪,你可以想一想我們已經編譯并運行了一個程序。因為我們將一點一點為這個程序添加功能,所以我們必須保證讓它能夠運行。似乎每個剛開始學編

3、程的程序員都想一下子編一個1000行的程序,然后一次修改所有的錯誤。沒有人,我是說沒有人,能做到這個。你應該先編一個可以運行的小程序,修改它,然后再次讓它運行。這可以限制你一次修改的錯誤數(shù)量。另外,你知道剛才做了哪些修改使程序無法運行,因此你知道應該把注意力放在哪里。這可以防止這樣的情況出現(xiàn):你認為你編寫的東西應該能夠工作,它也能通過編譯,但它就是不能運行。請切記,能夠通過編譯的程序并不意味著它是正確的。下一步為我們的游戲編寫一個頭文件。頭文件把數(shù)據類型和函數(shù)聲明集中到了一處。這可以保證數(shù)據結構定義的一致性,以便程序的每一部分都能以同樣的方式看待一切事情。#ifndef DECK_H#defi

4、ne DECK_H#define DECKSIZE 52 typedef struct deck_tint cardDECKSIZE;int dealt;deck_t;#endif把這個文件保存為deck.h。只能編譯.c文件,所以我們必須修改game.c。在game.c的第2行,寫上#includedeck.h。在第5行寫上deck_t deck;。為了保證我們沒有搞錯,把它重新編譯一次。gcc-o game game.c如果沒有錯誤,就沒有問題。如果編譯不能通過,那么就修改它直到能通過為止。預編譯編譯器是怎么知道deck_t類型是什么的呢?因為在預編譯期間,它實際上把deck.h文件復制到

5、了game.c文件中。源代碼中的預編譯指示以#為前綴。你可以通過在gcc后加上-E選項來調用預編譯器。gcc-E-o game_precompile.txt game.c wc-l game_precompile.txt3199 game_precompile.txt幾乎有3200行的輸出!其中大多數(shù)來自stdio.h包含文件,但是如果你查看這個文件的話,我們的聲明也在那里。如果你不用-o選項指定輸出文件名的話,它就輸出到控制臺。預編譯過程通過完成三個主要任務給了代碼很大的靈活性。把include的文件拷貝到要編譯的源文件中。用實際值替代define的文本。在調用宏的地方進行宏替換。這就使你能

6、夠在整個源文件中使用符號常量(即用DECKSIZE表示一付牌中的紙牌數(shù)量),而符號常量是在一個地方定義的,如果它的值發(fā)生了變化,所有使用符號常量的地方都能自動更新。在實踐中,你幾乎不需要單獨使用-E選項,而是讓它把輸出傳送給編譯器。編譯作為一個中間步驟,gcc把你的代碼翻譯成匯編語言。它一定要這樣做,它必須通過分析你的代碼搞清楚你究竟想要做什么。如果你犯了語法錯誤,它就會告訴你,這樣編譯就失敗了。人們有時會把這一步誤解為整個過程。但是,實際上還有許多工作要gcc去做呢。匯編as把匯編語言代碼轉換為目標代碼。事實上目標代碼并不能在CPU上運行,但它離完成已經很近了。編譯器選項-c把.c文件轉換為

7、以.o為擴展名的目標文件。如果我們運行gcc-c game.c我們就自動創(chuàng)建了一個名為game.o的文件。這里我們碰到了一個重要的問題。我們可以用任意一個.c文件創(chuàng)建一個目標文件。正如我們在下面所看到的,在連接步驟中我們可以把這些目標文件組合成可執(zhí)行文件。讓我們繼續(xù)介紹我們的例子。因為我們正在編寫一個紙牌游戲,我們已經把一付牌定義為deck_t,我們將編寫一個洗牌函數(shù)。這個函數(shù)接受一個指向deck類型的指針,并把一付隨機的牌裝入deck類型。它使用drawn數(shù)組跟蹤記錄那些牌已經用過了。這個具有DECKSIZE個元素的數(shù)組可以防止我們重復使用一張牌。#include stdlib.h#incl

8、ude stdio.h#include time.h#includedeck.hstatic time_t seed=0;void shuffle(deck_t*pdeck)int drawnDECKSIZE=0;int i;if(0=seed)seed=time(NULL);srand(seed);for(i=0;i DECKSIZE;i+)int value=-1;dovalue=rand()%DECKSIZE;while(drawnvalue!=0);drawnvalue=1;printf(%in,value);pdeck-cardi=value;pdeck-dealt=0;return

9、;把這個文件保存為shuffle.c。我們在這個代碼中加入了一條調試語句,以便運行時,能輸出所產生的牌號。這并沒有為我們的程序添加功能,但是現(xiàn)在到了關鍵時刻,我們看看究竟發(fā)生了什么。因為我們的游戲還在初級階段,我們沒有別的辦法確定我們的函數(shù)是否實現(xiàn)了我們要求的功能。使用那條printf語句,我們就能準確地知道現(xiàn)在究竟發(fā)生了什么,以便在開始下一階段之前我們知道牌已經洗好了。在我們對它的工作感到滿意之后,我們可以把那一行語句從代碼中刪掉。這種調試程序的技術看起來很粗糙,但它使用最少的語句完成了調試任務。以后我們再介紹更復雜的調試器。請注意兩個問題。我們用傳址方式傳遞參數(shù),你可以從&(取地址)操作符

10、看出來。這把變量的機器地址傳遞給了函數(shù),因此函數(shù)自己就能改變變量的值。也可以使用全局變量編寫程序,但是應該盡量少使用全局變量。指針是C的一個重要組成部分,你應該充分地理解它。我們在一個新的.c文件中使用函數(shù)調用。操作系統(tǒng)總是尋找名為main的函數(shù),并從那里開始執(zhí)行。shuffle.c中沒有main函數(shù),因此不能編譯為獨立的可執(zhí)行文件。我們必須把它與另一個具有main函數(shù)并調用shuffle的程序組合起來。運行命令gcc-c shuffle.c并確定它創(chuàng)建了一個名為shuffle.o的新文件。編輯game.c文件,在第7行,在deck_t類型的變量deck聲明之后,加上下面這一行:shuffle

11、(&deck);現(xiàn)在,如果我們還象以前一樣創(chuàng)建可執(zhí)行文件,我們就會得到一個錯誤gcc-o game game.c/tmp/ccmiHnJX.o:In functionmain:/tmp/ccmiHnJX.o(.text+0xf):undefined reference toshufflecollect2:ld returned 1exit status譯成功了,因為我們的語法是正確的。但是連接步驟卻失敗了,因為我們沒有告訴編譯器shuffle函數(shù)在哪里。那么,到底什么是連接?我們怎樣告訴編譯器到哪里尋找這個函數(shù)呢?連接連接器ld,使用下面的命令,接受前面由as創(chuàng)建的目標文件并把它轉換為可執(zhí)行文

12、件gcc-o game game.o shuffle.o這將把兩個目標文件組合起來并創(chuàng)建可執(zhí)行文件game。連接器從shuffle.o目標文件中找到shuffle函數(shù),并把它包括進可執(zhí)行文件。目標文件的真正好處在于,如果我們想再次使用那個函數(shù),我們所要做的就是包含deck.h文件并把shuffle.o目標文件連接到新的可執(zhí)行文件中。象這樣的代碼重用是經常發(fā)生的。雖然我們并沒有編寫前面作為調試語句調用的printf函數(shù),連接器卻能從我們用#include stdlib.h語句包含的文件中找到它的聲明,并把存儲在C庫(/lib/libc.so.6)中的目標代碼連接進來。這種方式使我們可以使用已能正

13、確工作的其他人的函數(shù),只關心我們所要解決的問題。這就是為什么頭文件中一般只含有數(shù)據和函數(shù)聲明,而沒有函數(shù)體。一般,你可以為連接器創(chuàng)建目標文件或函數(shù)庫,以便連接進可執(zhí)行文件。我們的代碼可能產生問題,因為在頭文件中我們沒有放入任何函數(shù)聲明。為了確保一切順利,我們還能做什么呢?另外兩個重要選項-Wall選項可以打開所有類型的語法警告,以便幫助我們確定代碼是正確的,并且盡可能實現(xiàn)可移植性。當我們使用這個選項編譯我們的代碼時,我們將看到下述警告:game.c:9:warning:implicit declaration of functionshuffle這讓我們知道還有一些工作要做。我們需要在頭文件中

14、加入一行代碼,以便告訴編譯器有關shuffle函數(shù)的一切,讓它可以做必要的檢查。聽起來象是一種狡辯,但這樣做可以把函數(shù)的定義與實現(xiàn)分離開來,使我們能在任何地方使用我們的函數(shù),只要包含新的頭文件并把它連接到我們的目標文件中就可以了。下面我們就把這一行加入deck.h中。void shuffle(deck_t*pdeck);這就可以消除那個警告信息了。另一個常用編譯器選項是優(yōu)化選項-O#(即-O2)。這是告訴編譯器你需要什么級別的優(yōu)化。編譯器具有一整套技巧可以使你的代碼運行得更快一點。對于象我們這種小程序,你可能注意不到差別,但對于大型程序來說,它可以大幅度提高運行速度。你會經常碰到它,所以你應該

15、知道它的意思。調試我們都知道,代碼通過了編譯并不意味著它按我們得要求工作了。你可以使用下面的命令驗證是否所有的號碼都被使用了game|sort-n|less并且檢查有沒有遺漏。如果有問題我們該怎么辦?我們如何才能深入底層查找錯誤呢?你可以使用調試器檢查你的代碼。大多數(shù)發(fā)行版都提供著名的調試器:gdb。如果那些眾多的命令行選項讓你感到無所適從,那么你可以使用KDE提供的一個很好的前端工具KDbg。還有一些其它的前端工具,它們都很相似。要開始調試,你可以選擇然后找到你的game程序。當你按下F5鍵或選擇Execution-從菜單運行時,你可以在另一個窗口中看到輸出。怎么回事?在那個窗口中我們什么也

16、看不到。不要擔心,KDbg沒有出問題。問題在于我們在可執(zhí)行文件中沒有加入任何調試信息,所以KDbg不能告訴我們內部發(fā)生了什么。編譯器選項-g可以把必要的調試信息加入目標文件。你必須用這個選項編譯目標文件(擴展名為.o),所以命令行成了:gcc-g-c shuffle.c game.c gcc-g-o game game.o shuffle.o這就把鉤子放入了可執(zhí)行文件,使gdb和KDbg能指出運行情況。調試是一種很重要的技術,很值得你花時間學習如何使用。調試器幫助程序員的方法是它能在源代碼中設置斷點。現(xiàn)在你可以用右鍵單擊調用shuffle函數(shù)的那行代碼,試著設置斷點。那一行邊上會出現(xiàn)一個紅色的

17、小圓圈?,F(xiàn)在當你按下F5鍵時,程序就會在那一行停止執(zhí)行。按F8可以跳入shuffle函數(shù)。呵,我們現(xiàn)在可以看到shuffle.c中的代碼了!我們可以控制程序一步一步地執(zhí)行,并看到究竟發(fā)生了什么事。如果你把光標暫停在局部變量上,你將能看到變量的內容。太好了。這比那條printf語句好多了,是不是?小結本文大體介紹了編譯和調試C程序的方法。我們討論了編譯器走過的步驟,以及為了讓編譯器做這些工作應該給gcc傳遞哪些選項。我們簡述了有關連接共享函數(shù)庫的問題,最后介紹了調試器。真正了解你所從事的工作還需要付出許多努力,但我希望本文能讓你正確地起步。你可以在gcc、as和ld的man和info page中

18、找到更多的信息。自己編寫代碼可以讓你學到更多的東西。作為練習你可以以本文的紙牌游戲為基礎,編寫一個21點游戲。那時你可以學學如何使用調試器。使用GUI的KDbg開始可以更容易一些。如果你每次只加入一點點功能,那么很快就能完成。切記,一定要保持程序一直能運行!要想編寫一個完整的游戲,你需要下面這些內容:一個紙牌玩家的定義(即,你可以把deck_t定義為player_t)。一個給指定玩家發(fā)一定數(shù)量牌的函數(shù)。記住在紙牌中要增加已發(fā)牌的數(shù)量,以便能知道還有那些牌可發(fā)。還要記住玩家手中還有多少牌。一些與用戶的交互,問問玩家是否還要另一張牌。一個能打印玩家手中的牌的函數(shù)。card等于value%13(得數(shù)

19、為0到12),suit等于value/13(得數(shù)為0到3)。一個能確定玩家手中的value的函數(shù)。Ace的value為零并且可以等于1或11。King的value為12并且可以等于10。GCC編譯選項解析GCC是Linux下基于命令行的C語言編譯器,其基本的使用語法如下。gccoption|對于編譯C+的源程序,其基本語法如下:g+option|其中option為GCC使用時的選項,而為需要GCC做編譯的處理的的文件名。就GCC來說,其本身是一個十分復雜的的命令,合理的使用其命令選項可以有效地提高程序的編譯效率、優(yōu)化代碼,GCC擁有眾多的命令選項,有超過100個的編譯選項可用,按其應有如下的分

20、類。常用編譯選項-c選項:這是GCC命令的常用選項。-c選項告訴GCC僅把源程序編譯為目標代碼而不做鏈接工作,所以采用該選項的編譯指令不會生成最終的可執(zhí)行程序,而是生成一個與源程序文件名相同的以.o為后綴的目標文件。例如一個Test.c的源程序經過下面的編譯之后會生成一個Test.o文件#gcc cTest.h-S選項:使用該選項會生成一個后綴名為.s的匯編語言文件,但是同樣不會生成可執(zhí)行程序。-e選項:-e選項只對文件進行預處理,預處理的輸出結果被送到標準輸出(比如顯示器)。-v選項:在Shell的提示符號下鍵入gcc v,屏幕上就會顯示出目前正在使用的gcc版本的信息.-x languag

21、e:強制編譯器指定的語言編譯器來編譯某個源程序。例如下面的指令:#gcc-x c+p1.c該指令表示強制采用C+編譯器來編譯C程序P1.c。-I DIR選項:庫依賴選項,指定庫及頭文件路徑。在Linux下開發(fā)程序的時候,統(tǒng)常來講都需要借助一個或多個函數(shù)庫的支持才能夠完成相應的功能。一般情況下,Linux下的大多數(shù)函數(shù)都將頭文件放到系統(tǒng)/usr/include目錄下,而庫文件則放到/usr/lib目錄下。但在有些情況下并不是這樣的,在這些情況下,使用GCC編譯時必須指定所需要的頭文件和庫文件所在的路徑。-I選項可以向GCC的頭文件搜索路徑中添加新的目錄DIR。例如,一個源程序所依賴的頭文件在用戶

22、/home/include/目錄下,此時就應該使用-I選項來指定。#gcc I/home/include-o test test.c-L DIR:類似于上面的情況,用來特別指定所依賴庫所在的路徑如果使用不在標準位置的庫,那么可以通過-L選項向GCC的庫文件搜索路徑中添加新的目錄。例如,一個程序要用到的庫libapp.so在/home/zxq/lib/目錄下,為了能讓GCC能夠順利地鏈接該庫,可以使用下面的指令:#gcc-Test.c-L/home/zxq/lib/-lapp oTest這里的-L選項表示GCC去鏈接庫文件libapp.so。在Linux下的庫文件在命名時遵循了一個約定,那就是應

23、該以lib三個字母開頭,由于所有的庫文件都遵循了同樣的規(guī)范,因此在使用-L選項指定鏈接的庫文件名時可以省去lib三個字母,也就是說GCC在對-lapp進行處理的時候,會自動去鏈接名為libapp.so的文件-static選項:GCC在默認情況下鏈接的是動態(tài)庫,有時為了把一些函數(shù)靜態(tài)編譯到程序中,而無需鏈接動態(tài)庫就采用-static選項,它會強制程序連接靜態(tài)庫。-o選項:在默認的狀態(tài)下,如果GCC指令沒有指定編譯選項的情況下會在當前目錄下生成一個名為a.out的可執(zhí)行程序,例如:執(zhí)行#gcc Test.c命令后會生成一個名為a.out的可執(zhí)行程序。因此,為了指定生成的可執(zhí)行程序的文件名,就可以采

24、用-o選項,比如下名的指令:#gcc oTest Test.c執(zhí)行該指令會在當前目錄下生成一個名為Test的可執(zhí)行文件。出錯檢查和警告提示選項GCC編譯器包含完整的出錯檢查和警告提示功能,比如GCC提供了30多條警示信息和3個警告級別,使用這些選項有助于增強程序的穩(wěn)定性和更加完善程序代碼的設計,此類選項常用的如下。-pedantic以ANSI/ISO C標準列出的所有警告當GCC在編譯不符合ANSI/ISO C語言標準的源代碼時,如果在編譯指令中加上了-pedantic選項,那么源程序中使用了擴展語法的地方將產生相應的警告信息。-w禁止輸出警告信息-Werror將所有警告轉換為錯誤Werror

25、選項要求GCC將所有的警告當成錯誤進行處理,這在使用自動編譯工具(如Make等)時非常有用。如果編譯時帶上-Werror選項,那么GCC會在所有產生警告的地方停止編譯,只有程序員對源代碼進行修改并起相應的警告信息消除時,才能夠繼續(xù)完成后續(xù)的編譯工作。-Wall顯示所有的警告信息-Wall選項可以打開所有類型的語法警告,以便于確定程序源代碼是否是正確的,并且盡可能實現(xiàn)可移植性。對Linux開發(fā)人員來講,GCC給出的警告信息是很有價值的,它們不僅可以幫助程序員寫出更加健壯的程序,而且還是跟蹤和調試程序的有力工具。建議在用GCC編譯源代碼時始終帶上-Wall選項,養(yǎng)成良好的習慣。代碼優(yōu)化選項代碼優(yōu)化是指編譯器通過分析源代碼找出其中尚未達到最優(yōu)的部分,然后對其重新進行組合,進而改善代碼的執(zhí)行性能。GCC通過提供編譯選項-On來控制

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論