1. 程式人生 > 程式設計 >C/C++的全緩衝、行緩衝和無緩衝

C/C++的全緩衝、行緩衝和無緩衝

1.簡介

C/C++中,基於I/O流的操作最終會呼叫系統介面read()和write()完成I/O操作。為了使程式的執行效率最高,流物件通常會提供緩衝區,以減少呼叫系統I/O介面的呼叫次數。

緩衝方式存在三種,分別是:
(1)全緩衝。輸入或輸出緩衝區被填滿,會進行實際I/O操作。其他情況,如強制重新整理、程序結束也會進行實際I/O操作。

對於讀操作來說,當讀入內容的位元組數等於緩衝區大小或者檔案已經到達結尾,或者強制重新整理,會進行實際的I/O操作,將外存檔案內容讀入緩衝區;對於寫操作來說,當緩衝區被填滿或者強制重新整理,會進行實際的I/O操作,緩衝區內容寫到外存檔案中。磁碟檔案操作通常是全緩衝的。

(2)行緩衝。輸入或輸出緩衝區遇到換行符會進行實際I/O操作。其他與全緩衝相同。

(3)無緩衝。沒有緩衝區,資料會立即讀入記憶體或者輸出到外存檔案和裝置上。標準錯誤輸出stderr是無緩衝的,這樣能夠保證錯誤資訊及時反饋給使用者,供使用者排除錯誤。

三種緩衝型別的巨集定義在標頭檔案<stdio.h>

緩衝型別 巨集
全緩衝 _IOFBF
行緩衝 _IOLBF
無緩衝 _IONBF

Linux環境下,下面一段程式碼可以很好地體現全緩衝和行緩衝的區別。

#include <stdio.h>
#include <stdlib.h>

int glob=6; 
int main(int argc,char** argv)
{
  int var; 
  pid_t pid; 
  printf("a write to stdout\n"); 
  if(pid=fork()<0)
  { 
    printf("fork error"); 
  }
  else
  { 
    if(pid==0)
    { 
      glob++; 
      var++; 
    } 
    else
    { 
      sleep(2); 
    } 
  } 
  printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var); 
  exit(0); 
}

編譯成功後預設生成a.out,執行結果如下:

./a.out
a write to stdout
pid=4823,glob=7,var=4195873
pid=4824,var=4195873

./a.out > temp.txt
cat temp.txt
a write to stdout
pid=4864,var=4195873
a write to stdout
pid=4865,var=4195873

可見printf在輸出到標準輸出(顯示器)時,是行緩衝,遇到換行符時會將緩衝區內容輸出到顯示器,並清空緩衝區。當使用重定向命令時,標準輸出被重定向到磁碟檔案,此時標準輸出變成全緩衝,遇到換行符不輸出,而是被拷貝至子程序中,在父子程序結束後,各有一份輸出。

2.緩衝區的設定

(1)緩衝開啟或關閉,可使用函式setbuf()或者setbuffer()。引數buf指向緩衝區,表示開啟緩衝,通常是全緩衝。將buf引數設定為NULL,表示關閉緩衝。注意,setbuffer()是非C標準庫函式,常見於Linux。

setbuf()的緩衝區長度至少為BUFSIZ(定義在stdio.h),否則可能會出現緩衝區溢位。setbuffer可以指定緩衝區大小。

//@header:stdio.h
//@brief:設定指定的緩衝區或關閉緩衝
//@param:stream:檔案指標;buffer:緩衝區地址
//@notice:使用預設緩衝大小BUFSIZ(在stdio.h中定義)
void setbuf ( FILE * stream,char * buffer );

//@notice:同setbuf,但可指定緩衝區大小
void setbuffer(FILE *stream,char *buf,size_t size);

將buffer指定為NULL,關閉標準輸出緩衝。

setbuf(stdout,NULL)

指定新的緩衝區。

static char newBuffer[BUFSIZ];//至少是BUFSIZ(定義在stdio.h),否則存在緩衝溢位可能
setbuf(stdout,(char*)&newBuffer);

//或者指定緩衝區大小
static char newBuffer[512];
setbuffer(stdout,(char*)&newBuffer,512);

(2)更改緩衝模式,可使用函式setvbuf()。

//@header:stdio.h
//@brief:更改緩衝模式並設定緩衝區
//@param:stream:檔案指標;buf緩衝區地址;type:緩衝區模式;size:緩衝區大小
//@ret:0成功,非0失敗
int setvbuf(FILE *stream,int type,unsigned size);

例如,將流緩衝區設定為行緩衝,呼叫setvbuf()時,緩衝區地址設為NULL,緩衝區大小設為0。注意,前提是存在緩衝區。

setvbuf(stream,NULL,_IOLBF,0); //將緩衝改為行緩衝

//上面的程式碼等價於
setlinebuf(stream);       //for Linux

如果呼叫setvbuf指定了緩衝區大小size大於0,緩衝區buf為NULL,則交由setvbuf進行malloc申請緩衝區。

//間接申請1024位元組全緩衝區
setvbuf(stream,_IOFBF,1024);

以上就是C/C++的全緩衝、行緩衝和無緩衝的詳細內容,更多關於C/C++ 緩衝的資料請關注我們其它相關文章!