本節書摘來自異步社群《linux 進階程式設計(第三版)》一書中的第1章,第1.2節,作者:楊宗德 , 呂光宏 , 劉雍著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視
linux 進階程式設計(第三版)
1.2.1 linux下c程式标準
在linux作業系統下進行c程式開發的标準主要有兩個:ansi c标準和posix标準。
ansi c标準是ansi(美國國家标準局)于1989年制定的c語言标準,後來被iso(國際标準化組織)接受為标準,是以也稱為iso c。
posix标準是最初由ieee開發的标準族,部分已經被iso接受為國際标準。
1.ansi c
ansi c的目标是為各種作業系統上的c程式提供可移植性保證(例如linux與windows之間),而不僅僅限于類unix系統。該标準不僅定義了c程式設計語言的文法和語義,而且還定義了一個标準庫。iso c标準定義的頭檔案如表1-1所示。
2.posix标準
posix.1和posix.2分别定義了相容作業系統的c語言系統接口以及工具标準。posix是類unix系統都遵循的标準,例如ubuntu下和redhat下沒有代碼不需要移植可直接編譯後執行,而在linux下基于posix标準完成的代碼就無法在Windows下直接編譯并執行。表1-2所示為26項posix标準定義的頭檔案,表1-3所示為26項posix标準定義的xsi擴充頭檔案,表1-4所示為8項posix标準定義的可選頭檔案。
1.2.2 庫函數和系統調用
1.系統調用函數和庫函數
庫函數用以完成常見的特定功能,通常由某一個組織制作釋出,并形成一定的标準,可以應用于不同的平台而不需要做任何修改即具有極好的移植性。例如,c函數庫能夠被絕大多數c編譯器支援。
系統調用函數一般與作業系統相關,不同的作業系統所使用的系統調用可能不同。一般來說,如果兩個作業系統差異很大,系統調用函數的可移植性就不高。例如windows采用了系統調用的應用程式不能直接在linux下編譯運作。系統調用函數很多情況下需要通路系統特殊資源,在linux下,系統調用采用軟中斷來實作,使用系統調用時,該程式的狀态将從使用者态切換到核心态。圖1-1所示為linux函數庫調用和系統調用示意圖。
庫函數在實作最終都需要使用系統調用,但它封裝了系統調用的部分操作,使用者不必關心它使用了哪些系統調用。另外,做上層應用程式開發時也沒有必要深入研究系統調用函數的具體實作過程。
2.glibc函數庫
衆所周知,c語言并沒有為常見的操作,例如輸入/輸出、記憶體管理等提供内置的支援。這些功能一般由标準的函數庫來提供。gnu的c函數庫glibc是linux最重要的函數庫,它定義了iso c标準指定的所有庫函數,以及由posix或其他unix作業系統變種指定的附加特色,還包括與gnu系統相關的擴充。目前,linux系統大多使用glibc 2.3以上的版本。glibc基于如下标準。
(1)iso c。c程式設計語言的國際标準,即ansi c。
(2)posix。gnu c函數庫實作了iso/iec 9945-1:1996(posix系統應用程式程式設計接口,即posix.1)指定的所有函數。該标準是對iso c的擴充,包括檔案系統接口原語、裝置相關的終端控制函數以及程序控制函數。同時,gun c函數庫還支援部分由iso/iec 9945-2:1993(posix shell和工具标準,即posix.2)指定的函數,其中包括用于處理正規表達式和模式比對的函數。
(3)berkeley unix(bsd和sunos)。gnu c函數庫定義了某些unix版本中尚未标準化的函數,尤其是4.2 bsd,4.3 bsd,4.4 bsd unix系統(即berkeley unix)以及sunos(流行的4.2 bsd變種,其中包含某些unix system v的功能)。bsd函數包括符号連接配接、select函數、bsd号處理函數以及套接字等。
(4) svid(system v的接口描述)。gnu c函數庫定義了大多數由svid指定而未被iso c和posix标準指定的函數。來自system v的支援函數包括程序間通信和共享記憶體、hsearch和drand48函數族、fmtmsg以及一些數學函數。
(5)xpg(x/open可移植性指南)。gnu c函數庫遵循x/open可移植性指南(issue 4.2)以及所有的xsi(x/open系統接口)相容系統的擴充,同時也遵循所有的x/open unix擴充。
3.系統調用
系統調用是作業系統提供給外部程式的接口。在c語言中,作業系統的系統調用一般通過函數調用的形式完成。因為這些函數封裝了系統調用的細節,将系統調用的入口、參數以及傳回值用c語言的函數調用過程實作。在linux系統中,系統調用函數定義在glibc中。系統調用需要注意以下幾點。
(1)系統調用函數通常在成功時傳回0值,不成功時傳回非零值。如果要檢查失敗原因,則要判斷全局變量errno的值,errno中包含錯誤代碼。
(2)許多系統調用的傳回資料通常通過引用參數傳遞。這時,需要在函數參數中傳遞緩沖區位址,而傳回的資料就儲存在該緩沖區中。
(3)不能認為系統調用函數比其他函數的執行效率高。因為系統調用是一個非常耗時的過程。
1.2.3 線上文檔介紹
linux是免費的自由軟體作業系統,大量的應用程式都是由自由組織和個人編寫,沒有特别大型的公司維護。是以,在程式中出現的大量問題都需要程式開發人員自己解決。一般的解決方案是檢視該程式的幫助檔案,因為linux開發人員在釋出其個人程式時都添加了詳細的幫助檔案。在linux系統下,常用的線上幫助檔案有man、info以及how-to等。最常用的是man手冊。
1.man手冊
man即manual,是unix系統手冊的電子版本。根據習慣,unix系統手冊通常分為不同的部分(或小節,即section),每個小節闡述不同的系統内容。目前的小節劃分如下。
man 1:指令,例如ls。可以檢視shell終端下指令使用介紹。
man 2:系統調用。可以檢視核心系統調用函數的描述,以及參數和傳回值情況。
man 3:函數庫調用。可以檢視普通函數庫中的函數。
man 4:特殊檔案。可以檢視/dev目錄中的特殊檔案。
man 5:檔案格式和約定。可以檢視/etc/passwd等檔案的格式,例如man /etc/passwd。
man 6:遊戲。
man 7:雜項和約定。标準檔案系統布局、手冊頁結構等雜項内容。
man 8:系統管理指令。隻有管理者使用的指令。
man 9:核心例程。非标準的手冊小節,便于linux核心的開發而包含其他手冊小節。
例如,常用指令行:
2.info手冊
linux中的大多數軟體開發工具都來自自由軟體基金會的gnu項目,這些工具軟體的線上文檔都以info檔案的形式存在。info程式是gnu的超文本幫助系統。info文檔一般儲存在/usr/info目錄下,使用info指令可以檢視info文檔。要運作“info”,可以在shell提示符後輸入“info”,也可以在gnu的emacs中鍵入“esc-x info”。
info幫助系統的初始螢幕顯示為一個主題目錄,可以将光标移動到帶有“*”的主題菜單上面,然後按Enter鍵進入該主題,也可以鍵入“m主題菜單的名稱”進入該主題。例如,你可以鍵入“m”,然後再鍵入“gcc”進入gcc主題中。如果要在主題之間跳轉,則必須記住如下幾個指令鍵。
n:跳轉到該節點的下一個節點。
p:跳轉到該節點的上一個節點。
m:指定菜單名。
f:進入交叉引用主題。
l:進入該視窗中的最後一個節點。
tab:跳轉到該視窗的下一個超文本連結。
ret:進入光标處的超文本連結。
u:轉到上一級主題。
d:回到info的初始節點目錄。
h:跳出info教程。
q:退出info。
3.how-to
可供使用者參考的聯機文檔的另一種形式是howto檔案,這些檔案位于系統的/usr/doc/howto目錄下。howto檔案的檔案名都有-howto字尾,并且都是文本檔案。每一個howto檔案包含linux某一方面的資訊,例如支援硬體或如何建立引導盤。要想檢視這些檔案,進入/usr/doc/howto目錄,使用more指令,具體形式如下:
<code>$ cd /usr/doc/howto;more topic-name-howto //切換到該目錄</code>
另外,還有其他格式的howto文檔,例如html和ps等,儲存在/usr/doc/howto/ other-formats下。
4.其他
linux的核心文檔一般包含在核心源代碼目錄/usr/src/'uname –r'/documentation/usr/doc中,該目錄下包含有大量與特定軟體或函數庫相關的說明性文檔。
1.2.4 擷取錯誤資訊
調用庫函數或系統調用函數後,如果執行成功将傳回0或者正确值;如果執行失敗,傳回 − 1,并把系統全局變量errno指派,以訓示具體的錯誤情況。該變量在檔案errno.h頭檔案中被聲明,具體如下所示:
所有的錯誤代碼都在errno.h檔案中定義。以下是/usr/include/asm/errno.h檔案部分内容:
為了列印出具體的errno值所對應的錯誤提示資訊,一般使用perror函數。此函數聲明如下:
另外,linux系統還提供了以下錯誤處理函數:
如果在應用程式中使用系統調用出錯後使用perror(),可将錯誤相關的消息寫入到标準錯誤輸出,描述調用系統函數或庫函數期間遇到的最後一個錯誤。perror()函數首先輸出參數字元串s,後接冒号、空格、消息和換行符。為發揮它最大的作用,參數字元串應包括導緻錯誤的程式的名稱。如下示例所示:
如果上例的chmod()函數調用失敗,将列印“stat: 具體的errno message”錯誤資訊。
錯誤編号取自符号errno,出錯時将設定此符号,但執行無錯誤調用後不會清除此符号。消息的内容與将errno用作參數的strerror()函數傳回的内容相同。如果給定了一個null字元串,則perror()函數隻輸出消息和換行符。