2011-05-17 74 views
7
#include <iostream> 
using std::cout; 
using std::endl; 
using std::cerr; 
#include <cstdio> 

int main() 
{ 
    char pbuffer[BUFSIZ]; 
    setbuf(stdout, pbuffer); 
    cout << "hello cout" ; 
    sleep(5); 
    cerr << "hello cerr"; 
    sleep(5); 
    cout << "\nAll done " << endl; 
    sleep(5); 
    return 0; 
} 

的緩衝後,我編譯和運行上面的程序,它的輸出是:爲什麼CERR刷新COUT

hello couthello cerr 
All done 

,但我認爲它應該是:

hello cerrhello cout 
All done 

我想知道,爲什麼cerr沖刷了cout的緩衝區?

+0

'cout <<「hello cout」;'before before'cerr <<「hello cerr」;' – iammilind 2011-05-17 06:28:37

+0

我想知道爲什麼cout的輸出會在cerr之前出現。我認爲cout的輸出是緩衝的,cerr的輸出應該先出來 – wildpointercs 2011-05-17 06:30:58

回答

7

這是設計。

cincerr都綁定到cout,並在任何自己的操作之前調用cout.flush()。

這個想法可能是輸入和輸出應該按正確的順序發生。

+0

這是錯誤的。 'cout'綁定到'cin',但就是這樣。 'cerr'不受任何束縛,也沒有任何束縛。 (這並不意味着該實現不使用其他同步機制,但是需要'cerr.tie()'來返回一個空指針。) – 2011-05-17 08:12:00

+0

快速檢查顯示VC8在這裏有一個錯誤:'cerr.tie ()'返回非null,儘管這是C++標準明確禁止的。 (g ++正確) – 2011-05-17 08:16:31

+0

@James - 在我的草稿副本中寫道:「在對象cerr初始化後,cerr.flags()&unitbuf'爲非零,'cerr.tie()'返回'&cout' 「。 (27.4.2) – 2011-05-17 08:18:34

7

首先,一個流只要感覺就可以刷新。我有可能在輸出到交互設備時,iostream的某些實現會改變緩衝策略。除非有意在兩個數據流的輸出之間進行刷新,否則它們出現的順序或多或少都是未指定的;所有你可以指望的是,一個<<cerr將不會有從cout插入到其中的字符。在你的情況下,實現以某種方式同步coutcerr。 (您可能希望看到如果將輸出重定向到不同的文件會發生什麼,或者到同一個非交互式文件— C++沒有區分交互設備和其他設備,但是C可以,我希望大多數C++實現遵循C in 。這方面)

FWIW,就爲了這兩個保證是:

  • cout綁定到cin,因此任何試圖在cin閱讀將刷新cout,並且
  • cerrunitbuf集,因此這將是 在每個<<運營商的末尾刷新。

背後後者的想法是,我認爲,以獲得類似於C的行緩衝的東西,這雖然如果你使用std::endl,你爲行緩衝的效果相同的C++不直接支持—。