12.21 O標準函數庫怎麼個“標準”法?

我們用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 <stdio.h>

int main(void)

{

int para = 0;

scanf("%d", ¶);

printf("=== %d ===\\n", 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,各自實現對文件的讀取、打開和寫入操作。

C語言I/O標準函數庫怎麼個“標準”法?

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上正常運行。

C語言I/O標準函數庫怎麼個“標準”法?

Linux系統API示意圖

Win、Linux等操作系統的API函數為了都能成為這種通用的標準的函數,它們都遵循了POSIX標準。

3、 標準函數庫的”標準“二字的理解

C語言標準函數庫的”標準“二字,就在於函數庫中的函數不使用系統級別函數還好,如果要使用系統級別函數,那麼必須調用通用的標準的系統API。有點繞好像!

這麼說吧:

  • 標準函數庫裡如果有函數不需要使用系統級別函數,那麼這些標準函數庫的函數就沒有標準不標準的概念,因為它們放到哪個系統上都可以不用做修改就能正常運行。為啥?因為它們就是不調用任何系統級別函數啊,自成一體,隨便放哪兒都能跑!
  • 標準函數庫裡如果有函數需要與底層的硬件打交道,那麼這些標準函數庫的函數實現不會去直接調用系統級別函數,而是會調用系統通用的標準的API。比如這些函數調用了上面所說的通用的標準的系統API:readAPI,那麼這些函數放在哪個系統上都不需要做任何修改就能正常地訪問硬件,讀取數據!

所以,所謂的C語言標準函數庫的”標準“,就是調用了系統通用的標準的API的意思。

三、一個簡單的示例

還以上面的那段C程序代碼為例:

#include <stdio.h>

int main(void)

{

int para = 0;

scanf("%d", ¶);

printf("=== %d ===\\n", para);

return 0;

}

在Win上的運行結果如下:

C語言I/O標準函數庫怎麼個“標準”法?

在Linux上的運行結果如下:

C語言I/O標準函數庫怎麼個“標準”法?

這段C程序代碼中的scanf函數和printf函數分別從鍵盤讀入數據、向屏幕輸出數據。

Win系統與Linux系統從鍵盤讀入數據、向屏幕輸出數據的系統級別函數的實現是不一樣的,但是它們均提供了通用的標準的系統API,scanf函數與printf函數均調用了這個通用的標準的系統API,因此這份C程序代碼未做任何修改就可以在兩個平臺上正常運行。因此scanf函數與printf函數是標準的IO函數!

四、庫函數又是如何做到非標準?

C語言中有標準的函數庫,那麼肯定也有非標準的函數庫。那麼請你思考下,非標準的函數庫的”非標準“三個字又該如何理解呢?歡迎在評論區留言!


分享到:


相關文章: