斯坦佛編程教程-Unix編程工具(一)

來源:互聯網
上載者:User

Unix編程工具
作者:Parlante, Zelenski等
Copyright 1998-2001, 斯坦佛大學
介紹
這篇文章介紹了基於Unix系統編程的整個過程,包括編輯-編譯-連結-調試。還極少了幾個普遍的Unix編程工具——gcc,make,gdb,emacs還有Unix shell。本文的目標是介紹這些工具的主要特徵和典型的使用方式並且足夠詳細地展示用它們共同來完成簡單的項目。我們已經在斯坦佛使用了這篇文章的一個版本來協助同學來開始Unix編程。

主要內容
介紹——編譯-連結的過程
gcc編譯器/連接器
make的功能
gdb調試器
emacs編輯器
Unix shell命令概述
http://cslibrary.stanford.edu/

(這是在斯坦佛電腦科學教學庫中的#107號文檔,叫做Unix編程工具.還有一些其他的免費的教學資料在http://cslibrary.stanford.edu/可以得到。這份文檔可以免費使用,和複製或是出售,只要它是完整並且沒有被篡改過。)

其它的資源
這個文檔只是對工具的一些介紹——想取得某個工具更詳細的資訊的話,請去查看工具的man頁面和xinfo中的詞條解釋。並且O'Reilly & Associates出版了一系列的關於Unix相關工具的書籍(那些書的封面都會有一種動物)。想學習基礎的C語言的話,請查看電腦教育庫的#101文檔,(http://cslibrary.stanford.edu/101/
)。

編譯的過程
在具體的去瞭解某個工具的細節之前,回顧一下編譯一個可執行檔的整個過程將是非常有用的。在源檔案被編輯好之後,build的分為兩個步驟:編譯和連結。每一個源檔案(foo.c)都會編譯成一個目標檔案(foo.o)。每一個目標檔案都包含著一個系統的依賴,編譯成程式的一個代表,就如同它在源檔案中描述的那樣。一個目標檔案的檔案名稱和源檔案的檔案名稱事一樣的,但是副檔名變成了“.o”——“main.c”編譯成了“main.o”.這個.o檔案將會包含程式所需要的引用,符號,方法,變數等等。
每一個單獨的目標檔案接下來就可以連結在一起並產生一個可以在系統上啟動並執行可執行檔。連結這一步也會將一些包含了庫方法(例如printf()和malloc())的庫檔案連結進來。整個的過程如:

第一部分——gcc
接下來我們要討論的事gcc編譯器,一個GNU(www.gnu.org)項目的開源產品。使用gcc有下面幾個好處——它會一直更新,並且十分可靠,它可以在多個平台運行,當然,它是免費和開源的。Gcc能編譯C,C++和objective-C。Gcc實際上既是一個編譯器又是一個連結器。對於簡單的問題,一個簡單的調用就能完成整個的編譯和連結操作。例如,對於一個簡單的項目你可能會使用下面的命令,作用是將三個.c檔案編譯連結在一起並產生一個叫做“program”的可執行檔。

gcc main.c module1.c module2.c -o program

上面的一行命名可以等價地分開寫成三條命令來建立項目。

gcc -c main.c ## Each of these compiles a .c
gcc -c module1.c
gcc -c module2.c
gcc main.o module1.o module2.o -o program ## This line links the .o's to build the program

調用gcc的一般命令是:
gcc options files

option一系列用於控制編譯器的選項,而files是gcc用於讀取或是寫入的列表

命令的選項

像大多數的Unix程式一樣,gcc支援大量的命令選項來控制它的運行。它們在gcc的man頁面都有介紹。我們能夠很安全地忽略掉其中大部分的命令選項,但下面幾個經常使用到的我們得注意:-c,-o,-g,-Wall,-I,-L和-l。

-c files 
直接用gcc將源檔案編譯到目標檔案而忽略掉連結的階段。Makefiles(下面會介紹)用這個選項來將多個檔案一次性編譯。

-o file
設定gcc的輸出檔案的檔案名稱必須是file。如果這個選項沒有被指明,那麼預設的名字得看情況。如果事編譯一個.c的源檔案,輸出的目標檔案將會和源檔案同名,但副檔名是.o。如果事連結產生一個可執行檔,輸出檔案將會被命名成a.out。大部分的時候,-o選項都只是用於在連結產生可執行檔時設定輸出檔案的檔案名稱,而在編譯的時候,人們只是用預設的設定來代替。

-g
指示編譯器在輸出中包含額外的調試資訊。我們建議你在編譯你的源檔案時加上這個選項,因為我們鼓勵你通過使用一些像gdb(下面會介紹)的調試器來變得更加熟練。

-Wall
給出原始碼裡可能存在的錯誤。使用了-Wall所得到的提示並不是真正的錯誤,他們只是編譯器認為可能的錯誤。我們非常建議你在編譯你的代碼的時候加上-Wall命令。在編譯的時候發現錯誤比在運行事發現錯誤簡單一萬倍。-Wall命令就像一個嘮叨的大媽,但她值得陪伴在你身邊。如果一個學生拿著一個運行不了的代碼來請教我,並且這些代碼在用-Wall命令編譯的時候產生了一些警告,那麼30%這些警告就是問題線索,30%可能不是,但你應該很開心它給了你免費的bug提示。

一些時候-Wall命令所得到的警告並不是真正的問題,代碼是正確的,並且編譯器也通過了編譯。這個時候,請不要忽視那些警告,請解決原始碼所產生的所有警告。放任警告不管是一個壞習慣。

下面事一個小的程式碼片段在一句代碼中給變數賦值並判斷其是否為真。
int flag;
if (flag = IsPrime(13)) {
...
}

編譯器會給出一個“可能不經意賦值”的警告,儘管這個情況中賦值事正確的,這個警告將會捕捉到一個普遍性的bug,就是當你想要輸入==的時候卻輸入了=。為瞭解決這個警告,重寫這個測試代碼...
int flag;
if ((flag = IsPrime(13)) != 0) {
...
}

這樣寫就不會有警告了,而產生的程式碼和之前的是一樣的。或者,你可以將整個測試代碼放入一個大括弧裡表明你的用意。這就是使用-Wall幫你找bug的價值。

-Idir
將dir目錄加入#include命令的搜尋命令。編譯器會自動地搜尋幾個標準目錄。使用這個選項可以增加編譯器的搜尋目錄。“-I”命令和目錄名之間沒有空格。如果因為#include命令無法找到檔案而編譯失敗,你需要用-I來解決它。

下面事怎樣利用unix中的“find”命令來尋找你的#include檔案。這個例子尋找/user/include目錄下的所有含有“inet”欄位的標頭檔...
nick% find /usr/include -name '*inet*'
/usr/include/arpa/inet.h
/usr/include/netinet
/usr/include/netinet6

-lmylib
(l是小寫)在連結的時候為未實現的標誌(方法或是全域變數)搜尋名為mylib的庫。庫的真正的名字應該事libmylib.a,並且這個庫要麼可以在系統的預設路徑下可以找到,要麼可以在用-L命令(下面會提到)添加的目錄中找到。

連結時,-l標誌在命令列表中的位置事非常重要的,因為連結器不會在先前檢查過的庫中搜尋未定義的標誌。例如,如果你在調用已一個依賴math庫的庫時,它必須在連結math庫之前被連結,否這就會報連結錯誤。和上面的那個命令一樣,命令符和庫名之間沒有空格,並且,這是一個小寫“L”,而不是數字1,如果在連結階段因為一個標誌未找到而失敗了,你就需要一個-l命令來加上合適的庫了,或者你可編譯的時候寫錯了函數的名字或是變數的名字。

-Ldir
將dir加入到由-l命令指明的庫的搜尋目錄。和上面的那個命令一樣,命令符和目錄名之間沒有空格。如果在連結的時候因為一個庫檔案沒有找到,你需要用-L命令來解決一下,或者你庫名寫錯了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.