我們用C語言編寫程式時,經常會用到“scanf”、“printf”等函數,這可是經典的輸入輸出函數。在Win上程式設計時會用到,在Linux上程式設計時會用到,在Mac上程式設計也會用到。你看,在這麼多系統平台上都會用到C語言的“scanf”、“printf”函數,你有沒有想過為啥它們不需要做任何修改就能用了?通吃大部分的平台啊!
因為“scanf”、“printf”等函數屬于I/O函數,是C語言标準函數庫的一部分。本文就來和你聊聊标準函數庫的“标準”到底标準在哪裡?
走起!
一、什麼是标準函數庫
“标準函數庫”= “函數庫” + “标準”。我們先來說說“函數庫”。
1、 什麼是函數庫?
我很喜歡逛超市,很喜歡沉浸在超市琳琅滿目的商品中,别問我為什麼有這癖好,因為小時候太窮,沒見過這麼多好吃的!逛着逛着我經常會看到超市裡面的商品倉庫,裡面有很多的進貨商品。超市貨架上什麼東西快賣光了,從業人員就會從倉庫裡及時取出補貨。
C語言中的函數庫,其實不僅僅是C語言啦,好多程式設計語言的函數庫差不多也是倉庫的意思。隻不過這個倉庫裡的商品都是“函數”:我們常見的scanf函數、printf函數、strcpy函數、strcat函數;abs函數、sin函數等,都放在這個函數庫裡。我們可愛的程式員GG和程式員MM,把我們程式設計中經常要用到的功能編寫出一個個函數,最終都放進這個函數庫供我們使用,是不是很感動!
雖然C語言的函數庫包含着衆多的可愛的函數,但是這些函數可不是無序的一盤散沙哦,而是被分成一個個的子庫。比如:
- 專門用于C程式輸入輸出的函數子庫。如scanf、printf、getchar、putchar等函數,把它們組織起來就是I/O函數子庫;
- 專門處理C程式字元串的函數子庫。如strcpy、strcat等函數,把它們組織起來就是字元串函數子庫;
- 專門處理數學運算的函數子庫。如fabs、asin等函數,把它們組織起來就是數學函數子庫;
- 還有什麼專門處理日期時間的函數子庫、通用工具的函數子庫等。有興趣的同學可以網上搜一把。
2、 什麼是标準的函數庫?
我平時程式設計的系統平台有Win和Linux。我在Win上編寫一個C程式代碼,如下:
#include
int main(void)
{
int para = 0;
scanf("%d", ¶);
printf("=== %d ===", para);
return 0;
}
其中用到了scanf函數和printf函數,在Win上運作沒問題。
這段C程式代碼拿到Linux上運作,scanf函數和printf函數依然正常運作。也就是說scanf函數和printf函數可以在Win和Linux上不需要做任何改變即可正常運作,這就是通用的意思,換個說法就是标準的意思,非常的标準。下面我們會進一步展開分析。
如果這段C程式代碼放在MAC上運作呢?這。。。我放下吃了三天的泡面,抹了一把辛酸淚,仰天長歎:”這輩子一定要攢夠錢買一台MAC“!
二、進一步解釋“标準”
要更深入地解釋C語言标準函數庫的”标準“含義,就要說到”系統級别函數“、”系統API“的話題了。
1、 系統級别函數
像Win、Linux等作業系統,它們本身會提供N多個函數供外部的第三方應用程式調用,也就是說作業系統開發商自己會寫一些函數,這些函數屬于作業系統的一部分。
假設Win作業系統自己提供了一個函數叫做:readWin,這個函數專門用于從鍵盤讀入資料的。假設現在Linux作業系統自己也提供了一個函數叫做:readLin,這個函數也是專門用于從鍵盤讀入資料的。readWin和readLin功能是一樣的,但它們内部具體實作,Win和Linux是不一樣的。
例如下圖以Linux為例,假設它有三個系統級别函數,分别是readLin、openLin、writeLin,各自實作對檔案的讀取、打開和寫入操作。
Linux系統級别函數示意圖
至于MAC。。。。我放下手中的泡面,又是一把辛酸淚!
2、 系統API
雖然說有了系統級别函數,我們自己編寫的應用程式就可以調用它們來實作讀取、寫入等通路硬體的操作,但是Win系統和Linux系統的程式員覺得這種直接調用系統級别函數還是不夠好,他們幹脆把這些衆多的系統級别函數又封裝了下,形成了系統API。
API,全稱是應用程式設計接口,其實也沒什麼玄乎的地方,說白了也是一個個的函數。也就是說,系統API的這些函數裡面使用了系統級别函數,也可能沒有使用系統級别函數。比如,win32 API的一系列函數内部調用了Win系統的系統級别函數。
假設Win系統有一個API叫做readAPI,它封裝了Win的系統級别函數readWin;再假設Linux系統有一個API也叫做readAPI,它封裝了Linux的系統級别函數readLin。那麼上面那段C程式代碼中的scanf函數隻要調用這個readAPI,那麼它就可以在Win上、Linux上不用做任何改變就可以正常運作。這裡函數readAPI就是一個通用的标準的函數。
例如下圖以Linux為例。假設它有兩個系統API,分别是readAPI和writeAPI。前者調用了系統級别函數readLin和openLin;後者隻是調用了系統級别writeLin。那麼C語言标準函數庫的函數隻會調用readAPI和writeAPI,而不會直接調用readLin、openLin、writeLin。這樣标準函數庫不需要做修改就可以在Win上正常運作。
Linux系統API示意圖
Win、Linux等作業系統的API函數為了都能成為這種通用的标準的函數,它們都遵循了POSIX标準。
3、 标準函數庫的”标準“二字的了解
C語言标準函數庫的”标準“二字,就在于函數庫中的函數不使用系統級别函數還好,如果要使用系統級别函數,那麼必須調用通用的标準的系統API。有點繞好像!
這麼說吧:
- 标準函數庫裡如果有函數不需要使用系統級别函數,那麼這些标準函數庫的函數就沒有标準不标準的概念,因為它們放到哪個系統上都可以不用做修改就能正常運作。為啥?因為它們就是不調用任何系統級别函數啊,自成一體,随便放哪兒都能跑!
- 标準函數庫裡如果有函數需要與底層的硬體打交道,那麼這些标準函數庫的函數實作不會去直接調用系統級别函數,而是會調用系統通用的标準的API。比如這些函數調用了上面所說的通用的标準的系統API:readAPI,那麼這些函數放在哪個系統上都不需要做任何修改就能正常地通路硬體,讀取資料!
是以,所謂的C語言标準函數庫的”标準“,就是調用了系統通用的标準的API的意思。
三、一個簡單的示例
還以上面的那段C程式代碼為例:
#include
int main(void)
{
int para = 0;
scanf("%d", ¶);
printf("=== %d ===", para);
return 0;
}
在Win上的運作結果如下:
在Linux上的運作結果如下:
這段C程式代碼中的scanf函數和printf函數分别從鍵盤讀入資料、向螢幕輸出資料。
Win系統與Linux系統從鍵盤讀入資料、向螢幕輸出資料的系統級别函數的實作是不一樣的,但是它們均提供了通用的标準的系統API,scanf函數與printf函數均調用了這個通用的标準的系統API,是以這份C程式代碼未做任何修改就可以在兩個平台上正常運作。是以scanf函數與printf函數是标準的IO函數!
四、庫函數又是如何做到非标準?
C語言中有标準的函數庫,那麼肯定也有非标準的函數庫。那麼請你思考下,非标準的函數庫的”非标準“三個字又該如何了解呢?歡迎在評論區留言!