printf行緩衝區的分析總結

 最近在客戶那調試串口的時候,read串口而後printf打印,單字符printf,發現沒有輸出,後來想起來printf這些標準輸入輸出函數也是屬於標準C庫glibc的,小程序

  這裏就要區分一下標準庫函數和系統調用了。網絡

  系統調用是內核提供給上層程序的接口,可以實現內核和上層之間的交互,系統調用在內核中的實現是軟中斷的方式,經過相應的中斷服務例程來實現,而標準庫函數是在系統調用的基礎之上封裝的應用程序,徹底運行在用戶態,在必要的時候調用系統調用。編寫應用程序能夠直接使用應用程序也可使用庫函數,那爲何還要有庫函數呢。函數

  以printf爲例,在printf的實現中,在調用write以前加入了IO緩衝區,這是一個用戶空間的緩衝,首先要說明一點,系統調用是軟中斷,頻繁調用,須要內核頻繁陷入內核態,這樣的效率不是很高,而printf實際是向用戶空間的IO緩衝寫,在知足條件的狀況下(條件下面會說)纔會調用write系統調用,這樣也就提升了內核的效率。spa

   對於普通的文件操做,庫函數由於IO緩衝區,效率高,其餘方面與直接調用系統調用無異,可是對於一些特殊的文件,如串口終端以及網絡設備。對於應用程序來將,咱們更加但願的是每次的操做可以真真正正的反映在底層的硬件上,這時咱們最好就不要使用相似與printf這樣的帶IO緩衝區的標準庫函數了,而是直接使用系統調用,我上面就是犯了這個錯誤。線程

   說完標準庫函數和系統調用的區別,咱們就要具體的分析一下printf。調試

    printf是一個行緩衝函數,先寫到緩衝區,知足條件後,纔將緩衝區刷到對應文件中,刷緩衝區的條件以下:接口

    1 緩衝區填滿進程

    2 寫入的字符中有‘\n’ '\r'it

    3 調用fflush手動刷新緩衝區io

    4 調用scanf要從緩衝區中讀取數據時,也會將緩衝區內的數據刷新

   

  知足上面4個條件之一緩衝區就會刷新,,也就是printf會真正調用write來寫入

   當咱們執行printf的進程或者線程結束的時候會主動調用flush來刷新緩衝區,因此程序結束,也會刷新

   若是咱們淪落到調用printf後再調用fflush來刷新的話,我感受還不如調用write來的直接呢

   其餘的3點都好理解,下面咱們就手動來研究一下printf的緩衝區到底有多大?

   這就須要咱們寫一個小程序來驗證一下,程序以下:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int i = 0x61;
    while(1)
    {   
        printf("%c", i); 
        i++;
        i = (i - 0x61) % 26 + 0x61;
        usleep(1000);
    }   
    return 0;
}

 

在本地機器上編譯這個程序,以後運行,在屏幕第一次輸出結構後ctrl+C殺死,將結果保存在一個文件中,ls -l查看一下這個文件

 我查看這個文件大小是1025個字節,這也就說明printf的緩衝區是1024byte,當寫入第1025字節時刷新緩衝區到終端下。

相關文章
相關標籤/搜索