stdout行緩衝和stderr無緩衝的含義

2021-08-20 22:43:34 字數 2310 閱讀 1629

有人說stdio是帶緩衝的,stderr是不帶緩衝的,這並不是指fd=1和fd=2這兩個裝置檔案,這兩個裝置是字元裝置,本身沒有快取。並且你看乙個程序的1和2兩個fd指向的其實是同乙個終端裝置檔案:

[root@ubuntu]arm-code:$ ls -l /proc/8669/fd/

total 0

lrwx------ 1 root root 64 4月 25 20:57 0 -> /dev/pts/7

lrwx------ 1 root root 64 4月 25 20:57 1 -> /dev/pts/7

lrwx------ 1 root root 64 4月 25 20:57 2 -> /dev/pts/7

所以,細想一下就知道,向1或2兩個fd寫東西,在核心裡走的是完全相同的路徑,不可能存在一會兒快取一會兒不快取的情況。

那上面說的「快取」到底是什麼東西呢?

如果你呼叫printf()或fwrite(…, stdout),進入標準庫後會先把要寫的內容放到乙個快取裡,直到遇到回車(或快取滿,比如緩衝最大1024位元組)或者程式退出(return和exit()會刷stdout快取),才會呼叫write系統呼叫進到核心裝置驅動實際去寫。這樣可以降低write系統呼叫的頻率,而向stderr寫東西就不在標準庫里做快取而是立即呼叫write去寫了。我們說stdout是行緩衝的,stderr是無緩衝的,就是這個意思,注意這裡的stdout和stderr是指標準庫里的file結構的指標,而不是標準輸出和標準錯誤裝置。

所以下面的程式,每個字串都沒有加回車,你就會看到先列印"ddddd",再一起列印"aaaaabbbbbccccc"。換成printf/perror或fprintf(stdout, …)/fprintf(stderr, …)也是一樣的結果。而你用write(1, …)和write(2, …)都是直接呼叫系統呼叫進核心,每次都會立即列印出來。

int main()

標準庫中的stream(即file結構的流檔案)有三種緩衝型別:

全緩衝(block buffered):以緩衝大小為限,例如4096位元組,則你fwrite到4kb後標準庫才會呼叫一次write去寫。

行緩衝(line buffered):以換行為限,當遇到newline的時候標準庫才會呼叫一次write去寫。不過如前面所說,行緩衝區也有大小限制,例如1024位元組,緩衝滿了也會去write。

無緩衝(unbuffered):在標準庫中不開闢緩衝區。

你也可以主動去清緩衝,使用fflush()即可:

#include int fflush(file *stream);
對於輸出流(例如向stdio或其他檔案寫東西),fflush(stream)將檔案在使用者態標準庫的緩衝全部刷到核心裡。對輸入流,fflush(stream)則丟棄所有尚未被應用程式拿到的緩衝資料。

如果引數stream為null,則fflush對所有開啟的輸出流檔案做刷緩衝操作。

除了fflush(),在對乙個檔案進行fseek()或fread()時,也會觸發呼叫write將緩衝寫進核心。

注:呼叫**fclose()**關閉檔案前也會呼叫fflush()刷使用者態緩衝的,並釋放緩衝區記憶體(fopen()開啟檔案的時候,會為這個fp申請緩衝用的空間,如4kb,每個fp有自己的緩衝區)。

另外我實驗exit()和return退出程式後也會清所有開啟檔案的緩衝區,而_exit()不會。如果程式異常退出(如未處理的ctrl+c訊號)也不會清緩衝區。

預設情況下,從終端的輸入輸出流都是行緩衝的,體現在諸如printf()/getchar()/putchar()等函式;stderr總是無緩衝的;其他檔案流是全緩衝的。

你可以通過setvbuf()等函式修改stream的緩衝型別和緩衝區大小:

#include void setbuf(file *stream, char *buf);

void setbuffer(file *stream, char *buf, size_t size);

void setlinebuf(file *stream);

int setvbuf(file *stream, char *buf, int mode, size_t size);

再補充一點,我們目前提到的都是使用者態的檔案緩衝,flush之後能保證將寫入內容提交給了核心。但對於塊裝置檔案系統中的檔案,仍不保證能真正寫到磁碟檔案中,因為核心的page cache還會做一層快取。

stdout行緩衝和stderr無緩衝的含義

有人說stdio是帶緩衝的,stderr是不帶緩衝的,這並不是指fd 1和fd 2這兩個裝置檔案,這兩個裝置是字元裝置,本身沒有快取。並且你看乙個程序的1和2兩個fd指向的其實是同乙個終端裝置檔案 root ubuntu arm code ls l proc 8669 fd total 0 lrwx...

python全緩衝 行緩衝和無緩衝

這裡的緩衝是指的是使用者空間的i o緩衝區,不是核心緩衝。上述都是i o緩衝區,其作用是減少read和write的次數,即減少了系統呼叫,從而減少了系統開銷,提高了i o速度。核心緩衝區。從理論上講,核心可以在任何時候寫磁碟,但並不是所有的write操作都會導致核心的寫動作。核心會把要寫的資料暫時存...

全緩衝和行緩衝的區別

在 nix系統中,緩衝方式存在三種,分別是 1,全緩衝 2,行緩衝 3,無緩衝 在學習apue這本書時,程式8 1中,就很好的體現了全緩衝和行緩衝的區別,如下 編譯成功後,我這裡生成的二進位制檔案預設為a.out 執行 a.out 可以看到結果如下 執行.a.out temp.out 結果如下 分析...