寫在前面的話:
i was so much order then, i'm younger than that now.
昔日我曾如此蒼老,如今才是風華正茂。
——bob dylan 《my back pages》
第3章 系統程式設計概念
本章主要講系統呼叫和庫函式的概念,以及對執行系統呼叫和庫函式之後的狀態進行檢查和診斷,這裡會介紹一組函式,而這些函式是本書作者自己編寫,並給出了函式的宣告和實現,本書中大多程式設計例項都會通過呼叫這些函式來診斷系統呼叫或庫函式的錯誤。最後,**可移植性問題。
一、系統呼叫
1、系統呼叫:核心提供的介面層(由核心函式實現),使用者程式通過這個系統呼叫介面來實現核心為我們寫好的各種功能。
2、對系統呼叫步驟,根據圖3-1作如下簡化(當然,本書作者的更加細緻,這裡只是為了好理解):
封裝函式----->系統呼叫介面----->系統呼叫例程------->系統呼叫服務例程(核心函式)
系統呼叫介面:通過軟中斷進入到核心空間,將系統呼叫的編號儲存到暫存器中。
系統呼叫例程:通過編號找到對應的核心函式(就是從存放所有呼叫服務例程的列表找),執行某乙個任務。
3、對書中「深入系統呼叫運作方式之前,關注一下幾點」,作如下理解:
1)處理器狀態的轉換,由使用者態(特權級3)轉換為核心態(特權級0),提高處理器的執行級別,以便於cpu訪問核心的記憶體
2)每乙個系統呼叫對應乙個編號
3)引數傳遞: 普通函式傳參通過將引數放入堆疊區,系統呼叫引數先儲存在cpu的暫存器中,在執行核心函式之前,放到核心堆疊區
二、庫函式
許多庫函式不會使用任何系統呼叫,還有些庫函式構建於系統呼叫之上。也就是說,一些庫函式是要通過系統呼叫實現的。
博主覺得這裡應該將系統呼叫與庫函式的區別指出,顯然本書是寫給對i/o程序有點基礎,想深入了解的讀者看的。博主水平有限,這裡只根據對檔案的讀寫方式的不同,來區別系統呼叫和庫函式:
我們將採用庫函式方式對檔案進行操作,叫做標準io;將採用系統呼叫的方式對檔案進行操作檔案io。
當對檔案進行操作的時候,檔案io直接通過系統呼叫對問進行讀寫;而標準i/o在使用者空間空間建立緩衝區,讀寫檔案時,先操作緩衝區,當滿足條件時,進行實際讀寫操作。這樣做,減少系統呼叫的次數,提高對檔案的讀寫效率
檔案io的操作核心是檔案描述符,而標準io的操作核心是流指標。(關於檔案io,第四章和第五章將會介紹)
三、處理來自系統呼叫和庫函式的錯誤
在進行錯誤檢查時必須堅持首先檢查函式的返回值是否表明呼叫出錯,然後再檢查erron(錯誤號)確定錯誤原因。常用的做法之一是根據erron值來列印錯誤訊息,庫函式perror()和strerror()可以實現這一目的。
作者在本節中一直在強調要檢查錯誤,書中也是這麼做的,如下面一段程式:
cnt = read(fd, buf, numbytes);
if(cnt == -1)
}
這段程式中,read是乙個系統呼叫函式,用if條件語句檢查函式的返回值是否為-1,如果為-1,說明呼叫出錯,然後再用if條件語句檢查erron確定錯誤原因。但是erron錯誤編號是有很多的,我們不可能將每個錯誤編號都判斷一遍,於是作者為了簡化程式中的錯誤處理,編寫了錯誤診斷函式。
現在讓我們當一回作者,考慮一下如何編寫錯誤診斷函式?
首先,診斷錯誤要用到錯誤號,先弄乙個陣列存放這些erron對應的符號名,錯誤處理函式會使用該陣列,去列印某個特定錯誤號相對應的符號名。作者這裡用了乙個陣列ename來存放錯誤名。為什麼要這麼做?一是因為strerror()不會標識出與錯誤訊息相對應的符號常量(如上例中的eintr就是符號常量,它的錯誤號是4);另一方面,手冊頁在描述錯誤時,使用的是符號名稱,列印出符號名稱便於讀者在手冊頁中查詢錯誤原因。
接下來就要實現這些函式了,作者在這裡定義了六個錯誤處理函式,errmsg()、errexit()、err_exit()、errexiten()、fatal()、usageerr()、cmdlineerr()
這六個處理函式有各自的特點和使用範圍,作者在書中已經有詳細的說明,並在程式清單3-3中有它們的實現。我們不需要現在就記住這些函式是使用,只要在以後看到作者的程式清單用到了某個函式,考慮一下為什麼在這裡用,這樣便能理解這些函式。
現在我們來研究一下程式清單3-3,看這幾個函式是如何實現的。
從函式宣告來看,這幾個函式都是可變引數的,那麼獲取引數列表中的引數就是解決問題的關鍵。只要獲取了可變引數,接下來按照p41~p43對每個函式的介紹,可以很容易理解。
裡面有幾個清單中用到的函式:
typedef char* va_list;
void va_start ( va_list ap, prev_param );
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是乙個字元指標,可以理解為指向當前引數的乙個指標,取參必須通過這個指標進行。
在呼叫參數列之前,定義乙個 va_list 型別的變數,(假設va_list 型別變數被定義為ap);
然後應該對ap 進行初始化,讓它指向可變參數列裡面的第乙個引數,這是通過 va_start 來實現的,第乙個引數是 ap 本身,第二個引數是在變參表前面緊挨著的乙個變數,即「...」之前的那個引數;
然後是獲取引數,呼叫va_arg,它的第乙個引數是ap,第二個引數是要獲取的引數的指定型別,然後返回這個指定型別的值,並且把 ap 的位置指向變參表的下乙個變數位置;
獲取所有的引數之後,我們有必要將這個 ap 指標關掉,以免發生危險,方法是呼叫 va_end,他是輸入的引數 ap 置為 null,應該養成獲取完參數列之後關閉指標的習慣。說白了,就是讓我們的程式具有健壯性。通常va_start和va_end是成對出現。
參考但是,作者在獲取引數時沒有呼叫va_arg,有的用到的是vfprintf()直接列印錯誤資訊;
參考而有的是呼叫自定義函式outputerror(),在這個函式中列印錯誤資訊。這個函式實現中呼叫了如下函式:
vsnprintf參考
snprintf參考
getenv參考
還有些用到的函式這裡沒有提及,遇到不會的借鑑一下別人的經驗,或者檢視man手冊,自己就能夠解決。
四、解析數值型命令列引數的函式
我們知道,命令列可以傳參,但數值型命令列引數傳入的是字串,要想把它轉換成整型數,我們可以用atoi()、atol()、srttol(),而作者提供了兩個函式getint()、getlong(),這兩個函式針對數值型引數提供了有效性檢查,即如果arg未包含乙個有效的整數字串(即僅包含數字以及「+」和「-」),那麼這兩個函式會列印一條錯誤訊息,並終止程式。
對於這兩個函式的實現,程式清單3-6可以很容易看明白,唯一令博主不明白的是作者預定義了幾個gn_*系列常量,與flag相或,是如何實現選擇進製轉換的?如果有研究過本段**的朋友希望可以指點一二。
五、可移植性問題
這一小節中,作者向我們介紹了怎樣編寫自己的程式才能具有可移植性。看我這小節突然明白了之前一些不明白但卻不影響學習的寫法,比如說為啥非要把int重新命名成pid_t。有些東西就是這樣,初看不明白,可以先跳過去看後面的,等再次看的時候反而更加理解了。好了,如何使程式具有可移植性呢?博主把本小節歸納為以下幾點:
1、特性測試巨集:控制標頭檔案顯露對特定標準的定義;
2、使用系統資料型別宣告變數;
3、正確初始化標準結構體;
4、使用預編譯指令#ifdef(因為有的巨集並不存在)。
六。課後練習
reboot()系統呼叫的引數magic2,沒見過,不要緊,隨便開個終端,man 2 reboot檢視一下,第二個引數magic2的取值有4個:
linux_reboot_magic2 (that is, 672274793)
linux_reboot_magic2a (that is, 85072278)
linux_reboot_magic2b (that is, 369367448)
linux_reboot_magic2c (that is, 537993216)
這四個數字轉換成十六進製制數分別是:
672274793=0x28121969
85072278=0x05121996
369367448=0x16041998
537993216=0x20112000
看出什麼來了嗎?是不是很像日期呢?day,month,year,沒錯,就是生日。問了度娘,原來是linux的作者linus torvalds自己和他三個女兒的生日。知道這個答案,我只想說一句:「原來可以這樣!」
如果有讀者看了已經發表過的這幾篇讀書筆記,會感覺到博主不是簡單的知識點羅列,而是將書中的概念進行梳理不至於會被翻譯弄的不知所云,博主在寫每篇讀書筆記時都會潛心研究書中內容,將已經具備的知識和書中內容進行融合,力求將此博文寫成本書解析,最好可以冠以名為」linux系統程式設計手冊解析「。博主很樂意與別人分享知識和經驗,這樣做既可以幫助別人,也可以提高自己。
讀書筆記之linux unix系統程式設計手冊 43
程序間通訊介紹 1.unix系統上各種通訊和同步工具,並根據功能將他們分成了三類 1 通訊 這些工具關注程序之間的資料交換 2 同步 這些程序關注程序和執行緒操作之間的同步 3 訊號 儘管訊號的主要作用並不在此,但在特定場景下可以將它作為一種同步技術 2.資料傳輸工具 為了通訊,乙個程序將資料寫入i...
《Linux UNIX系統程式設計手冊》第1章讀書筆記
寫在前面的話 一切偉大的行動和思想都有乙個眇乎小哉的開始。第1章 歷史和標準 看第1章題目就可以知道本章要講的是歷史和標準。我們會問,歷史是講誰的歷史?1.unix和c語言的歷史 這段歷史已經聽過很多了,要注意它是at t公司整出來的,其中c語言完全是為了實現unix核心及相關軟體而開發的。注意其中...
《Linux UNIX系統程式設計手冊》第2章讀書筆記
寫在前面的話 紅燭啊!你流一滴淚,灰一分心。灰心流淚你的果,創造光明你的因。紅燭啊!莫問收穫,但問耕耘。第2章 基本概念 本章講了很多基本概念,有的概念會貫穿全書,有的概念作者只簡單提了一下,後面的章節會有深入講解。對於這些概念,博主不一一介紹,而是將其中有聯絡的概念放到一起說。一 linux系統的...