日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux c学习--从标准输入输出看流和缓冲区

發(fā)布時(shí)間:2023/12/9 linux 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux c学习--从标准输入输出看流和缓冲区 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

學(xué)習(xí)標(biāo)準(zhǔn)輸入輸出,我們都會(huì)遇到一個(gè)概念,流和緩沖區(qū),但到底什么是流,什么是緩沖區(qū)呢?

????? 書(shū)《C Primer Plus》上說(shuō),C程序處理一個(gè)流而不是直接處理文件。后面的解釋十分抽象:流(stream)是一個(gè)理想化的數(shù)據(jù)流,實(shí)際輸入或輸出映射到這個(gè)數(shù)據(jù)流。這個(gè)流具體是一個(gè)怎么樣的東西呢?

流這個(gè)定義非常的形象。我們可以這樣理解:
???? 你聲明一個(gè)FILE *fp ,并把fopen(某個(gè)文件)返回的值賦予fp這兩個(gè)動(dòng)作就相當(dāng)于建立了一個(gè)水龍頭,當(dāng)你用getc(fp)之類(lèi)的輸入函數(shù)讀取文件字符時(shí)就相當(dāng)于擰開(kāi)了水龍頭,每讀取一個(gè)字符,這個(gè)文件就像水一樣的流動(dòng)一下,fp所指的地址自然就向后移動(dòng)了一位。 [cpp]?view plaincopy
  • int?ch;??
  • while((ch=getc(fp))!=EOF)??
  • ????putchar(ch);??

  • ???????你看這個(gè)循環(huán),可以讀取一個(gè)文件的所有字符。如果不是流的話,ch永遠(yuǎn)是第一個(gè)字符,不會(huì)更新。也可以理解為,fp自動(dòng)++(一個(gè)字符的大小)。 ???? 但流的概念意味著什么呢?
    --流是獨(dú)立于設(shè)備之外而操縱外設(shè)一種邏輯手段。?
    --大多數(shù)外設(shè)都是互異的,所以(操縱)它們需要專(zhuān)門(mén)的編程技術(shù)。?
    --流對(duì)程序員隱藏這些不同點(diǎn),而準(zhǔn)許他們以同樣的方式來(lái)處理大多數(shù)外設(shè)。?
    --考慮到一連串的字符需要一次讀一個(gè),流(相當(dāng)于)是具有緩沖作用的接口。?
    --個(gè)人計(jì)算機(jī)都是基于流架構(gòu)的。

    各大權(quán)威對(duì)流的說(shuō)法有些不一致,我認(rèn)為流既是數(shù)據(jù)的源或目的地的抽象,也是源和目的地之間流動(dòng)信息的表示。但流起碼都暗含以下的幾個(gè)方面:?
    1、流是一個(gè)抽象的概念,是對(duì)信息的一種表達(dá);在程序中,流就是對(duì)某個(gè)對(duì)象輸入輸出信息的抽象。就像運(yùn)輸工具是對(duì)一切運(yùn)動(dòng)載體的抽象一樣。?
    2、流是一種“動(dòng)”的概念,靜止存儲(chǔ)在介質(zhì)上的信息只有當(dāng)它按一定的序列準(zhǔn)備“運(yùn)動(dòng)”時(shí)才稱(chēng)為流。“從程序移進(jìn)或移出字節(jié)”就是“動(dòng)”的表現(xiàn)。靜止的信息具有流的潛力,但不一定是流,就像沒(méi)有汽油不能行走的汽車(chē)一樣,它具有運(yùn)輸工具的潛力,但它還不是運(yùn)輸工具(因?yàn)樗苡锌赡鼙划?dāng)作房子來(lái)用了,我就在大街上看見(jiàn)有精明的商人用火車(chē)車(chē)廂來(lái)做酒吧)。
    3、流有源頭也有目的地;程序中各種移動(dòng)的信息都有其源和目的,記得編程(特別是匯編)時(shí),老是要確定好某個(gè)操作的源操作數(shù)和目的操作數(shù)。借用佛教一言也即是:“萬(wàn)物皆有因果”,這也就像長(zhǎng)江一樣,西自唐古拉,而東去太平洋。在高速公路上飛跑的汽車(chē),它必有其出發(fā)地和目的地。
    4、流一定帶有某種信息,沒(méi)有任何內(nèi)容的流帶著自身來(lái)表達(dá)“空”信息。就像運(yùn)輸工具一樣,它不運(yùn)貨的時(shí)候就運(yùn)著自己這一身的零件(包括駕駛員)并把一樣?xùn)|西運(yùn)到目的地,那就是它自己和一個(gè)“跑空車(chē)”的信息。流有最小的信息單元就是二進(jìn)制位,含有最小的信息包就是字節(jié),C標(biāo)準(zhǔn)庫(kù)提供兩種類(lèi)型的流:二進(jìn)制流(binary?stream)和文本流(text?stream)。二進(jìn)制流是有未經(jīng)處理的字節(jié)構(gòu)成的序列;文本流是由文本行組成的序列。而在著名的UNIX系統(tǒng)中,文本流和二進(jìn)制流是相同的(identical)。
    5、流有源頭也有目的地,那么它必定與源頭和目的地相關(guān)聯(lián)。但人們操作流的時(shí)候,最關(guān)心的還是其目的地,也就是一個(gè)定向(orientation)的意思,就像司機(jī)運(yùn)貨一樣,它首要關(guān)心的問(wèn)題是目的地,而非起點(diǎn)(操作者都知道)。在C語(yǔ)言中,通過(guò)打開(kāi)流來(lái)關(guān)聯(lián)流及其目的地,使用的函數(shù)是fopen(),該函數(shù)返回一個(gè)指向文件的指針(FILE?*),該指針包含了足夠的可以控制流準(zhǔn)確地到達(dá)目的地的信息。
    FILE是一個(gè)結(jié)構(gòu)體(摘自TC2.0中stdio.h文件)
    ? [cpp]?view plaincopy
  • /*?Definition?of?the?control?structure?for?streams?
  • */??
  • typedef?struct??{??
  • ????????short???????????level;??????????/*?fill/empty?level?of?buffer?*/??
  • ????????unsigned????????flags;??????????/*?File?status?flags????*/??
  • ????????char????????????fd;?????????????/*?File?descriptor??????*/??
  • ????????unsigned?char???hold;???????????/*?Ungetc?char?if?no?buffer?*/??
  • ????????short???????????bsize;??????????/*?Buffer?size??????????*/??
  • ????????unsigned?char???*buffer;????????/*?Data?transfer?buffer?*/??
  • ????????unsigned?char???*curp;??????????/*?Current?active?pointer?*/??
  • ????????unsigned????????istemp;?????????/*?Temporary?file?indicator?*/??
  • ????????short???????????token;??????????/*?Used?for?validity?checking?*/??
  • }???????FILE;???????????????????????????/*?This?is?the?FILE?object?*/??

  • ???? 將它稱(chēng)為流控制結(jié)構(gòu)體(control?structure?for?streams)真好表現(xiàn)出其功能來(lái)。舉個(gè)例子就好像一卡車(chē)司機(jī)要把貨物運(yùn)到X公司,公司主管就會(huì)給他一張地圖及X公司的基本信息,這些材料所提供的信息如果足夠的話,那么它就能指導(dǎo)著司機(jī)準(zhǔn)確地將貨物送達(dá)了。C中FILE這個(gè)結(jié)構(gòu)體所起的作用就好像是運(yùn)輸公司把一切有用的指導(dǎo)信息封裝起來(lái)的檔案袋一樣。而已有關(guān)聯(lián)的流要終止這種關(guān)聯(lián),就必須關(guān)閉流,使用的函數(shù)是fclose(),就像運(yùn)貨公司若不再給X公司運(yùn)貨了,那么他們就必須要終止合作協(xié)議了。
    ????這里要注意的是:C語(yǔ)言中stdin、stdout、stderr分別是標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流及標(biāo)準(zhǔn)出錯(cuò)流的邏輯目的,他們都默認(rèn)對(duì)應(yīng)相應(yīng)的物理終端。在程序運(yùn)行伊始,不需要進(jìn)行open()操作,流自動(dòng)打開(kāi)。

    ? 那緩沖區(qū)又是什么意思呢? 緩沖區(qū)(Buffer):?
    ? ? 為了匹配計(jì)算機(jī)快速設(shè)備和慢速設(shè)備間的通信步伐,計(jì)算機(jī)中大量使用硬件緩沖區(qū)(如CPU中的Cache,內(nèi)存相對(duì)于硬盤(pán)和CPU),流是傳輸信息的一種邏輯表示,對(duì)流的各種不同操作也可能存在使用緩沖的需求。但是這里的buffer只是一種邏輯概念,不是物理設(shè)備。緩沖區(qū)存在于流與具體的設(shè)備終端或者存儲(chǔ)介質(zhì)上的文件之間。就好像運(yùn)貨到一個(gè)公司里一樣,合同上的要求是運(yùn)到X公司,但是實(shí)際上是真的把貨物運(yùn)到X公司的總部大樓嗎?不是。應(yīng)該是運(yùn)到X公司的倉(cāng)庫(kù)中。這里的倉(cāng)庫(kù)就有點(diǎn)像我們所說(shuō)的緩沖區(qū)了。也可以這么說(shuō),流運(yùn)動(dòng)到目的,先經(jīng)過(guò)的是緩存區(qū)。 ? 以scanf() printf()為例:????????????????????? ??? 緩沖區(qū)(流)負(fù)責(zé)在輸入/輸出設(shè)備和程序之間建立聯(lián)系。 –輸入設(shè)備->內(nèi)存緩沖區(qū)(stdin)->程序 –程序->內(nèi)存緩沖區(qū)(stdout)->輸出設(shè)備 ??? 是一塊臨時(shí)的存儲(chǔ)區(qū)域,或在內(nèi)存中,或在設(shè)備的控制卡上 ? ? . 緩沖類(lèi)型。

    標(biāo)準(zhǔn)庫(kù)提供緩沖是為了減少對(duì)read和write的調(diào)用。提供的緩沖有三種類(lèi)型(整理自APUE):

    • 全緩沖。

    在這種情況下,實(shí)際的I/O操作只有在緩沖區(qū)被填滿(mǎn)了之后才會(huì)進(jìn)行。對(duì)駐留在磁盤(pán)上的文件的操作一般是有標(biāo)準(zhǔn)I/O庫(kù)提供全緩沖。緩沖區(qū)一般是在第一次對(duì)流進(jìn)行I/O操作時(shí),由標(biāo)準(zhǔn)I/O函數(shù)調(diào)用malloc函數(shù)分配得到的。

    術(shù)語(yǔ)flush描述了標(biāo)準(zhǔn)I/O緩沖的寫(xiě)操作。緩沖區(qū)可以由標(biāo)準(zhǔn)I/O函數(shù)自動(dòng)flush(例如緩沖區(qū)滿(mǎn)的時(shí)候);或者我們對(duì)流調(diào)用fflush函數(shù)。

    • 行緩沖

    在這種情況下,只有在輸入/輸出中遇到換行符的時(shí)候,才會(huì)執(zhí)行實(shí)際的I/O操作。這允許我們一次寫(xiě)一個(gè)字符,但是只有在寫(xiě)完一行之后才做I/O操作。一般的,涉及到終端的流--例如標(biāo)注輸入(stdin)和標(biāo)準(zhǔn)輸出(stdout)--是行緩沖的。

    • 無(wú)緩沖

    標(biāo)準(zhǔn)I/O庫(kù)不緩存字符。需要注意的是,標(biāo)準(zhǔn)庫(kù)不緩存并不意味著操作系統(tǒng)或者設(shè)備驅(qū)動(dòng)不緩存。

    當(dāng)然,我們常用的scanf()? 與? printf() 屬于行緩沖,下面我們來(lái)看個(gè)例子,可以幫助我們理解緩沖區(qū)在標(biāo)準(zhǔn)輸入輸出中的作用: [cpp]?view plaincopy
  • <pre?class="cpp"?name="code">#include?<stdio.h>??
  • ??
  • int?main()??
  • while(1);??
  • {??
  • ????printf("hello?world");??
  • ????while(1);??
  • }??
  • 我們看看輸出結(jié)果: [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/char1$?gcc?-o?1?1.c??
  • fs@ubuntu:~/qiang/char1$?./1??
  • 打出是個(gè)空的,為什么呢?

    我們上面提到標(biāo)準(zhǔn)輸入輸出是行緩沖,即一行滿(mǎn)了才會(huì)刷新,那什么是刷新呢?刷新就是將數(shù)據(jù)從緩沖區(qū)取出來(lái),真正能刷新,要滿(mǎn)足什么條件呢?

    1、滿(mǎn)刷新,即一行滿(mǎn)了(1024個(gè)字節(jié))才會(huì)刷新;

    2、遇到'\n'會(huì)刷新;

    3、調(diào)用fflush()函數(shù);

    4、程序結(jié)束 fclose();

    我們可以看到上面的程序,應(yīng)為有while(1),程序一直沒(méi)有結(jié)束,沒(méi)有'\n',沒(méi)有滿(mǎn)行,沒(méi)有fflush(),所以并不會(huì)輸出;

    這樣理解的話,我們可以改動(dòng)一下了,就寫(xiě)一個(gè)吧,加'\n':

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • ??
  • int?main()??
  • {??
  • ????printf("helloworld\n");??
  • ????while(1);??
  • }??
  • 執(zhí)行結(jié)果如下:

    [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/char1$?gcc?-o?1?1.c??
  • fs@ubuntu:~/qiang/char1$?./1??
  • helloworld??


  • 總結(jié)

    以上是生活随笔為你收集整理的Linux c学习--从标准输入输出看流和缓冲区的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。