1. 程式人生 > >C/C++ 輸入輸出緩衝區在Windows和Linux下對比

C/C++ 輸入輸出緩衝區在Windows和Linux下對比

C++中cin、cout,cerr和C的stdin、stdout、stderr都是同步的,即iostream 物件和 and cstdio流是同步的,同步關係如下:這裡寫圖片描述

同步即表明我們可以在程式中混合用cout和printf或其他對應的流對。可以用std::ios_base::sync_with_stdio(false)來取消這種同步,取消後,如下程式中cout和printf就不是按照預期的順序輸出

std::ios_base::sync_with_stdio(false); 
    for(int i = 0 ; i < 10; i++) 
    { 
        cout<<"1 "
; printf("2 "); }

windows下輸出是:2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
linux下是:1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2
正是因為這種同步,所以cin、cout比scanf、printf速度要慢,如果我們在使用cin、cout輸入輸出前加一句std::ios_base::sync_with_stdio(false),其實速度和scanf、printf差不多。

for(int i = 0 ; i < 10; i++) 
    { 
        cout
<<"1 "; } while(1); //在windows下立即輸出10個1 //linux下不輸出 //說明windows下預設cout是無緩衝的,linux下是有緩衝的,cout換成printf也是一樣。

只有緩衝區被重新整理的時候緩衝區中的內容才會寫入真實的檔案或輸出裝置上。這五種情況下會重新整理輸出緩衝區:
1.程式正常結束。作為main返回工作的一部分,將清空所有的輸出緩衝區。
2.在一些不確定的時候,緩衝區可能已經滿了,在這種情況下,緩衝區將會在寫下一個值之前重新整理。
3.用操縱符顯示地重新整理緩衝區,如用endl。
4.在每次輸出操作執行完畢後,用unitbuf操縱符設定流的內部狀態,從而清空緩衝區。
5.可將輸出流與輸入流關聯起來,在讀輸入流時將重新整理其關聯的輸出緩衝區。

我們可以通過函式setbuf 和 setvbuf 自己設定輸入輸出流的緩衝區,需要注意的是不管程式中申請的的緩衝區實際大小為多少,setbuf都將緩衝區設定的大小為BUFSIZ, 本人也在某本書上看到一個sample
args = emalloc(BUFSIZ);
這是stdio.h 中的一個巨集定義,內容如下:

/* Default buffer size. */
#ifndef BUFSIZ
    define BUFSIZ _IO_BUFSIZ
#endif

BUFSIZ有一個_IO_BUFSIZ大小,這個_IO_BUFSIZ又是多大呢?
#define _IO_BUFSIZ _G_BUFSIZ
來自libio.h標頭檔案,那麼接著……
#define _G_BUFSIZ 8192
來自_G_config.h,最終確認BUFSIZ大小是8192,還有更快的方法就是cout這個BUFSIZ,直接出現大小。(以上三段程式碼在fedora25環境下測試)

setvbuf則可以設定緩衝區大小以及緩衝區的模式(行緩衝、全緩衝、無緩衝),需要注意的是這兩個函式設定的是c的輸入輸出緩衝區,因為C++和C的緩衝區是同步的,所有該函式會對C++有影響

  char buf[1024];
  setbuf(stdout, buf);
  for(int i = 0 ; i < 10; i++) 
    { 
      cout<<"1 "; 
    } 
  while(1);//此時windows下輸出了10個1,linux下沒有任何輸出。
  //因為windows是通過cmd視窗設定緩衝區
  //更改對應登錄檔鍵值或者設定即可

因為預設情況下,cin是和cout繫結的,cin 會重新整理cout的緩衝區,可以用函式cin.tie(0)來解繫結。所以在上面程式碼的基礎上,在while(1); 前面加上:int a; cin>>a; 此時所有的1就可以輸出了。

char buf[1024];
setbuf(stdout, buf);
for(int i = 0 ; i < 10; i++) 
    { 
      cout<<"1 "; 
    }
int a; cin>>a; 
while(1);//linux windows均輸出1

加上cin.tie(0)後,以下的程式碼沒有輸出1,因為cin已經和cout解綁定了,cin重新整理不了cout的緩衝區。(可以cin.tie(&cout)來繫結,注意cout沒有tie方法)

char buf[1024];
setbuf(stdout, buf);
cin.tie(0);
for(int i = 0 ; i < 10; i++) 
    { 
       cout<<"1 "; 
    }
int a; cin>>a; 
while(1);//windows和linux下均沒有輸出。

有點奇怪的是以下程式碼還是會輸出1,即預設緩衝區的情形下,解除繫結沒有產生效果。SOF上有人這麼解釋。

cin.tie(0);
for(int i = 0 ; i < 10; i++) 
    { 
        cout<<"1 "; 
    }
int a; cin>>a; 
while(1);