2017-03-08 87 views
5

我讀「UNIX網絡編程:套接字聯網API」和示例代碼,他們有一個錯誤處理功能,其中包含以下行:爲什麼在寫stderr之前需要在stdout上使用fflush?

fflush(stdout);  /* in case stdout and stderr are the same */ 
fputs(buf, stderr); 
fflush(stderr); 

凡buf將包含一個錯誤的描述。我不明白爲什麼fflush在第一行的標準輸出上使用,以及爲什麼評論解釋了它的使用原因。

回答

11

這是因爲緩衝。 Stdout and stderr are usually buffered differently。標準輸出爲通常爲行緩衝,意味着它將不會顯示輸出,直到它看到一個換行符。 Stderr是通常是無緩衝,並會立即打印,思維是你應該看到錯誤信息pronto。

但他們都去同一個地方,終端。這就是/* in case stdout and stderr are the same */的含義。他們通常是。但是因爲它們的緩衝區不同,這可能會導致它們無序顯示。

請考慮這段代碼。請注意缺乏換行符。

#include <stdio.h> 

int main() { 
    fprintf(stdout, "This is to stdout. "); 
    fprintf(stderr, "This is to stderr. "); 
    fprintf(stdout, "This is also to stdout. "); 
} 

你所期望的輸出是:

This is to stdout. This is to stderr. This is also to stdout. 

但事實並非如此。這是無序的。

$ ./test 
This is to stderr. This is to stdout. This is also to stdout. 

輸出到stderr立即顯示,它是無緩衝的。雖然stdout必須等待直到標準輸出緩衝區被換行符刷新。沒有換行符,所以程序退出時會刷新。

通過在使用標準錯誤之前清除標準輸出,您可以確保輸出按照正確的順序進行,無論緩衝如何。

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

int main() { 
    fprintf(stdout, "This is to stdout. "); 
    fflush(stdout); 
    fprintf(stderr, "This is to stderr. "); 
    fprintf(stdout, "This is also to stdout. "); 
} 

$ ./test 
This is to stdout. This is to stderr. This is also to stdout. 

這確保錯誤消息以正確的順序與正常消息一起出現。這可以避免混淆哪些錯誤信息適用於程序的哪一部分。

+0

你的第二個例子是錯誤的; '這也是stdout.'和'這是stdout.'應該被切換。 – Qix

+0

如果'stderr'是反特徵緩衝的,那麼類似的問題將會發生,而這個答案並不能解決這個問題。在寫作之前,用筆尖沖洗另一個。或者使用良好的禮儀和[沖洗完成後] – chux

+1

@Qix謝謝。我最初混淆了代碼中的文件句柄。 – Schwern

1

如果stdout和stderr指向同一個文件,則必須確保首先寫入stdout緩衝區中的任何內容。

相關問題