C语言标准输入输出缓冲区
閱讀目錄
- 概念
- 緩沖區類型
- 1. 全緩沖
- 2. 行緩沖
- 3. 不帶緩沖
- 緩沖區特征
- 1. 緩存特征
- 2. 緩沖區的大小
- 3. 緩沖區的刷新(清空)
- 4. 緩沖類型和大小確認函數
- 緩沖實例
- FILE結構定義
- 參考資料
概念
緩沖區又稱為緩存,它是內存空間的一部分。也就是說,在內存空間中預留了一定的存儲空間,這些存儲空間用來緩沖輸入或輸出的數據,這部分預留的空間就叫做緩沖區。
緩沖區根據其對應的是輸入設備還是輸出設備,分為輸入緩沖區和輸出緩沖區。
為什么要引入緩沖區
比如我們從磁盤里取信息,我們先把讀出的數據放在緩沖區,計算機再直接從緩沖區中取數據,等緩沖區的數據取完后再去磁盤中讀取,這樣就可以減少磁盤的讀寫次數,再加上計算機對緩沖區的操作大大快于對磁盤的操作,故應用緩沖區可大大提高計算機的運行速度。
又比如,我們使用打印機打印文檔,由于打印機的打印速度相對較慢,我們先把文檔輸出到打印機相應的緩沖區,打印機再自行逐步打印,這時我們的CPU可以處理別的事情。
現在您基本明白了吧,緩沖區就是一塊內存區,它用在輸入輸出設備和CPU之間,用來緩存數據。它使得低速的輸入輸出設備和高速的CPU能夠協調工作,避免低速的輸入輸出設備占用CPU,解放出CPU,使其能夠高效率工作。
緩沖區類型
緩沖區 分為三種類型:全緩沖、行緩沖和不帶緩沖。
1. 全緩沖
在這種情況下,當填滿標準I/O緩存后才進行實際I/O操作。全緩沖的典型代表是對磁盤文件的讀寫。
一般磁盤文件是全緩沖的(緩沖區一般為4096個字節)。
2. 行緩沖
在這種情況下,當在輸入和輸出中遇到換行符時,執行真正的I/O操作。這時,我們輸入的字符先存放在緩沖區,等按下回車鍵換行時才進行實際的I/O操作。典型代表是標準輸入(stdin)和標準輸出(stdout)。
注意:換行符也被讀入緩沖區。(緩沖區一般為1024個字節)
3. 不帶緩沖
也就是不進行緩沖,標準出錯情況stderr是典型代表,這使得出錯信息可以直接盡快地顯示出來。
緩沖區特征
1. 緩存特征
ANSI C( C89 )要求緩存具有下列特征:
當且僅當標準輸入和標準輸出并不涉及交互設備時,它們才是全緩存的。
標準出錯決不會是全緩存的。
但是,這并沒有告訴我們如果標準輸入和輸出涉及交互作用設備時,它們是不帶緩存的還是行緩存的,以及標準輸出是不帶緩存的,還是行緩存的。
大部分系統默認使用下列類型的緩存:
標準出錯是不帶緩存的。
如果是涉及終端設備的流,則它們是行緩存的;否則是全緩存的。
我們經常要用到標準輸入輸出流,而ANSI C對stdin、stdout和stderr的緩存特征沒有強行的規定,以至于不同的系統可能有不同的stdin、stdout和stderr的緩存特征。目前主要的緩存特征是:stdin和stdout是行緩存;而stderr是無緩存的。
2. 緩沖區的大小
如果我們沒有自己設置緩沖區的話,系統會默認為標準輸入輸出設置一個緩沖區,這個緩沖區的大小通常是4096個字節的大小,這和計算機中的分頁機制有關,因為進程在計算機中分配內存使用的就是分頁與分段的機制,并且每個頁的大小是4096個字節,因此通常情況下緩沖區的大小會設置為4096個字節的大小。
緩沖區大小由stdio.h頭文件中的宏BUFSIZ定義,如果希望查看它的大小,包含頭文件,直接輸出它的值即可。
#include <stdio.h>int main() {printf("<stdio.h> BUFSIZ:%d\n",BUFSIZ);return 0; }緩沖區的大小是可以改變的,也可以將文件關聯到自定義的緩沖區,詳情可以查看setbug()和setvbuf()函數。
https://www.runoob.com/cprogramming/c-function-setbuf.html
https://www.runoob.com/cprogramming/c-function-setvbuf.html
3. 緩沖區的刷新(清空)
下列情況會引發緩沖區的刷新:
緩沖區滿時;
行緩沖區遇到回車時;
關閉文件;
使用特定函數刷新緩沖區,如fflush()函數
我們上面提到標準輸入輸出是行緩沖,即一行滿了才會刷新,那什么是刷新呢?刷新就是將數據從緩沖區取出來,真正能刷新,要滿足什么條件呢?
1、滿刷新,即一行滿了(1024個字節)才會刷新;
2、遇到’\n’會刷新;
3、調用fflush()函數;
4、程序結束 fclose();
4. 緩沖類型和大小確認函數
//這是一個分別打印三個標準流和一個文件流的緩沖方式的應用實例 #include <stdio.h> #include <stdlib.h>#if defined(MACOS) #define _IO_UNBUFFERED __SNBF #define _IO_LINE_BUF __SLBF #define _IO_file_flags _flags #define BUFFERSZ(fp) (fp)->_bf._size #else #define BUFFERSZ(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base) #endif //以上是關于緩沖方式和緩沖區大小的預定義 void pr_stdio(const char *, FILE *); //子函數聲明 int main(int argc,char *argv[]) {FILE *fp = NULL; //流文件結構指針pr_stdio("stdin", stdin); //標準輸入pr_stdio("stdout", stdout); //標準輸出pr_stdio("stderr", stderr); //標準出錯處理printf("fopen error\n");fp = fopen("file.txt", "w+");fprintf(fp, "%s %s %s %d", "We", "are", "in", 2020);pr_stdio("file", fp); //文件return 0; } //測試緩沖輸出函數 void pr_stdio(const char *name, FILE *fp) { printf("當前流是%s, ", name); //打印流的名稱if (fp->_IO_file_flags & _IO_UNBUFFERED){printf("無緩沖\n");}else if (fp->_IO_file_flags & _IO_LINE_BUF){printf("行緩沖\n");}else{ printf("全緩沖\n");}printf(", 緩沖區大小 = %ld\n", BUFFERSZ(fp));return; }https://blog.51cto.com/10638473/1983077
緩沖實例
我們以printf函數和stderr為例,先說明stdout(對應printf)是遇到換行符或緩沖區滿之后或程序結束后才輸出緩沖,stderr一般是無緩沖的:
/* ** 在我的實驗環境中,緩沖區大小默認為1024 */ #include <stdio.h>int main() {while(1) {printf(".");fprintf(stderr, "1");}return 0; }運行結果:
(你可以數數,有1024個1,然后1024個’.’,…)
或者你可以通過用./a.out > t 2>&1重定向標準輸出和錯誤到文件t中,這樣就可以很容易看到運行結果(因為程序跑的很快,很難找到開始運行出來的那一行),這時的緩沖區大小是4096個字節。
FILE結構定義
頭文件
<sys/reent.h> defines __FILE, _fpos_t.默認定義
struct __sFILE {unsigned char *_p; /* current position in (some) buffer */int _r; /* read space left for getc() */int _w; /* write space left for putc() */short _flags; /* flags, below; this FILE is free if 0 */short _file; /* fileno, if Unix descriptor, else -1 */struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */int _lbfsize; /* 0 or -_bf._size, for inline putc */#ifdef _REENT_SMALLstruct _reent *_data; #endif/* operations */_PTR _cookie; /* cookie passed to io functions */_READ_WRITE_RETURN_TYPE _EXFNPTR(_read, (struct _reent *, _PTR,char *, _READ_WRITE_BUFSIZE_TYPE));_READ_WRITE_RETURN_TYPE _EXFNPTR(_write, (struct _reent *, _PTR,const char *,_READ_WRITE_BUFSIZE_TYPE));_fpos_t _EXFNPTR(_seek, (struct _reent *, _PTR, _fpos_t, int));int _EXFNPTR(_close, (struct _reent *, _PTR));/* separate buffer for long sequences of ungetc() */struct __sbuf _ub; /* ungetc buffer */unsigned char *_up; /* saved _p when _p is doing ungetc data */int _ur; /* saved _r when _r is counting ungetc data *//* tricks to meet minimum requirements even when malloc() fails */unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */unsigned char _nbuf[1]; /* guarantee a getc() buffer *//* separate buffer for fgetline() when line crosses buffer boundary */struct __sbuf _lb; /* buffer for fgetline() *//* Unix stdio files get aligned to block boundaries on fseek() */int _blksize; /* stat.st_blksize (may be != _bf._size) */_off_t _offset; /* current lseek offset */#ifndef _REENT_SMALLstruct _reent *_data; /* Here for binary compatibility? Remove? */ #endif#ifndef __SINGLE_THREAD___flock_t _lock; /* for thread-safety locking */ #endif_mbstate_t _mbstate; /* for wide char stdio functions. */int _flags2; /* for future use */ };參考資料
https://www.cnblogs.com/pricks/p/3821832.html
https://www.cnblogs.com/mydomain/p/9817320.html
https://blog.csdn.net/snowlyw/article/details/80963494
總結
以上是生活随笔為你收集整理的C语言标准输入输出缓冲区的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯云搭建Cpolar内网穿透
- 下一篇: [已解决] ‘strncpy‘ outp