linux系統呼叫和庫函式呼叫的區別
Linux下對檔案操作有兩種方式:系統呼叫(system call)和庫函式呼叫(Library functions)。可以參考《Linux程式設計》(英文原版為《Beginning Linux Programming》,作者是Neil Matthew和Richard Stones)第三章: Working with files。系統呼叫實際上就是指最底層的一個呼叫,在linux程式設計裡面就是底層呼叫的意思。面向的是硬體。而庫函式呼叫則面向的是應用開發的,相當於應用程式的api,採用這樣的方式有很多種原因,第一:雙緩衝技術的實現。第二,可移植性。第三,底層呼叫本身的一些效能方面的缺陷。第四:讓api也可以有了級別和專門的工作面向。
1、系統呼叫
系統呼叫提供的函式如open, close, read, write, ioctl等,需包含標頭檔案unistd.h。以write為例:其函式原型為 size_t write(int fd, const void *buf, size_t nbytes),其操作物件為檔案描述符或檔案控制代碼fd(file descriptor),要想寫一個檔案,必須先以可寫許可權用open系統呼叫開啟一個檔案,獲得所開啟檔案的fd,例如 fd=open(\"/dev/video\", O_RDWR)。fd是一個整型值,每新開啟一個檔案,所獲得的fd為當前最大fd加1。Linux系統預設分配了3個檔案描述符值:0-standard input,1-standard output,2-standard error。
系統呼叫通常用於底層檔案訪問(low-level file access),例如在驅動程式中對裝置檔案的直接訪問。
系統呼叫是作業系統相關的,因此一般沒有跨作業系統的可移植性。
系統呼叫發生在核心空間,因此如果在使用者空間的一般應用程式中使用系統呼叫來進行檔案操作,會有使用者空間到核心空間切換的開銷。事實上,即使在使用者空間使用庫函式來對檔案進行操作,因為檔案總是存在於儲存介質上,因此不管是讀寫操作,都是對硬體(儲存器)的操作,都必然會引起系統呼叫。也就是說,庫函式對檔案的操作實際上是通過系統呼叫來實現的。例如C庫函式fwrite()就是通過write()系統呼叫來實現的。
這樣的話,使用庫函式也有系統呼叫的開銷,為什麼不直接使用系統呼叫呢?這是因為,讀寫檔案通常是大量的資料(這種大量是相對於底層驅動的系統呼叫所實現的資料操作單位而言),這時,使用庫函式就可以大大減少系統呼叫的次數。
2、庫函式呼叫
標準C庫函式提供的檔案操作函式如fopen, fread, fwrite, fclose, fflush, fseek等,需包含標頭檔案stdio.h。以fwrite為例,其函式原型為size_t fwrite(const void *buffer, size_t size, size_t item_num, FILE *pf),其操作物件為檔案指標FILE *pf,要想寫一個檔案,必須先以可寫許可權用fopen函式開啟一個檔案,獲得所開啟檔案的FILE結構指標pf,例如pf=fopen(\"~/proj/filename\", \"w\")。實際上,由於庫函式對檔案的操作最終是通過系統呼叫實現的,因此,每開啟一個檔案所獲得的FILE結構指標都有一個核心空間的檔案描述符fd與之對應。同樣有相應的預定義的FILE指標:stdin-standard input,stdout-standard output,stderr-standard error。
庫函式呼叫通常用於應用程式中對一般檔案的訪問。
庫函式呼叫是系統無關的,因此可移植性好。
由於庫函式呼叫是基於C庫的,因此也就不可能用於核心空間的驅動程式中對裝置的操作。
※函式庫呼叫 VS 系統呼叫函式庫呼叫 | 系統呼叫 |
在所有的ANSI C編譯器版本中,C庫函式是相同的 | 各個作業系統的系統呼叫是不同的 |
它呼叫函式庫中的一段程式(或函式) | 它呼叫系統核心的服務 |
與使用者程式相聯絡 | 是作業系統的一個入口點 |
在使用者地址空間執行 | 在核心地址空間執行 |
它的執行時間屬於“使用者時間” | 它的執行時間屬於“系統”時間 |
屬於過程呼叫,呼叫開銷較小 | 需要在使用者空間和核心上下文環境間切換,開銷較大 |
在C函式庫libc中有大約300個函式 | 在UNIX中大約有90個系統呼叫 |
典型的C函式庫呼叫:system fprintf malloc | 典型的系統呼叫:chdir fork write brk; |