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++ 緩衝的資料請關注我們其它相關文章!