c語言檔案操作解析(五)之eof解析
在c語言中,有個符號大家都應該很熟悉,那就是eof(end of file),即檔案結束符。但是很多時候對這個理解並不是很清楚,導致在寫**的時候經常出錯,特別是在判斷檔案是否到達檔案末尾時,常常出錯。
1.eof是什麼?
在vc中檢視eof的定義可知:
#define eof (-1)
eof只是代表乙個整形常量-1。因此很多人認為在檔案的末尾存在這個結束標誌eof,這種觀點是錯誤的。事實上在檔案的末尾是不存在這個標誌的。那麼有人會問那下面的程式如何解釋?
char ch;while((ch=fgetc(fp))!=eof)
書上都通過這樣的**去判斷是否讀取到文字檔案末尾,就是當讀取到eof的時候就結束操作。這種理解是錯誤的。
先看一下函式fgetc的原型:
int fgetc(file *fp);
事實上在fgetc函式內部,每次都是讀取乙個位元組的資料,而且這乙個位元組的資料是以unsigned即無符號型處理的,然後將這乙個位元組的資料賦給乙個int型變數作為返回值返回,因此無論從檔案中讀取的是什麼資料,作為無符號型賦值給乙個int型變數,返回值不可能是負數。比如當讀取到資料0xfa時,因為是以無符號處理的,因此在將0xfa賦值給int型變數的時,int型變數的高位是填充0的(為什麼填充0,跟組合語言裡面的符號擴充套件類似,在後面會提到),因此返回的結果是0x00 00 00 fa,始終不會是負數.而若讀取到檔案末尾的時候,即沒有資料可供讀取的時候,那麼返回eof,即-1,這個-1是乙個int型常量,二進位制表示是0x ff ff ff ff。
上面的**具有很大的侷限性,因為其只能判斷是否到達文字檔案的末尾,而不能對二進位制檔案進行準確的判斷。因為正常情況下,文字檔案中無論如何是無法讀取到-1(0x ff)這個資料,因此可以判斷。但是對於二進位制檔案不同,很可能讀到的乙個位元組的資料就是0xff,那麼返回值此時就是-1,但是此時還未到達檔案末尾,造成錯誤的判斷。
那麼有沒有辦法解決?可以將ch定義為int型即可。
下面來比較一下下面這段程式和上面程式在執行時的區別。
int ch;while((ch=fgetc(fp))!=eof)
假如在檔案中讀取到的資料是0xfa。
那麼對於上面一段程式的執行過程是:
將0xfa先賦值給乙個int型變數(假如是a),那麼此時a為0x 00 00 00 fa,當將返回值a返回給變數ch時,由於ch是char型的,只有8位,那麼只將a的低8位賦給ch,那麼此時ch為0x fa,而ch是作為有符號處理的,那麼此時ch的值肯定是負數。
而若將ch定義為int型,執行過程為:
將0xfa先賦值給乙個int型變數(假如是a),那麼此時a為0x 00 00 00 fa,當將返回值a返回給變數ch時,由於ch也是int型的,因此ch為0x 00 00 00 fa,是乙個正數,兩段程式執行得到的結果完全不同。
下面看一下若讀取到的資料是0x ff(此時未到檔案末尾)時,是什麼結果。
若ch為char型,則當將返回值0x 00 00 00 ff返回時,取低8位賦給ch,那麼此時ch為-1,此時會誤判為到達檔案末尾;
而若ch為int型,則當將返回值0x 00 00 00 ff返回時,ch的值為0x 00 00 00 ff,此時ch不為-1,不會誤判為檔案末尾。
(當然上面所述成立必須是在讀取不出錯的情況下才成立)
所以很多情況下會用到函式feof.
二.feof
feof函式的原型是
int feof(file *fp);
若到達檔案末尾則返回乙個非零值,否則返回0。
在vc中檢視feof函式的定義:
#define _ioeof 0x0010
#define feof(_stream) ((_stream)->_flag & _ioeof)
可知feof函式判斷是否到達檔案末尾時與_flag這個標誌有關。
下面看一下這段程式:
#include#include
int main(void)
for(ch=65;ch<=70;ch++)
rewind(fp);
while(feof(fp)==0)
fclose(fp);
return
0;}
執行結果是:
4142
4344
4546
ffffffff
press any key to continue
為什麼最後列印結果會多列印乙個ffffffff?不是只往檔案中寫入了資料65-70麼?
先看一下c++ reference中關於feof函式的描述(c++ reference是乙個比較好的**,裡面是關於c++所有庫函式的描述,**在部落格首頁的鏈結中有,
stream
stream
從描述中可知,只有當與檔案關聯的流到達檔案末尾時,此時若再進行讀取操作,檔案結束的標誌(上面所述的_flag)才會被重新置位。
因此在上述程式中,當讀取完最後乙個位元組的資料後,檔案結束標誌並沒有被置位,只有當位置指標到達末尾時,再發生讀取操作時,而此時又沒有資料可供讀取,因此返回-1,所以列印出的結果中會多乙個ffffffff,在這之後才會將_flag重新置位,此時feof函式才能檢測出已經到達了檔案末尾。
那麼可以通過下面的辦法解決這個問題:
ch=fgetc(fp);while(feof(fp)==0)
這樣就不會多列印乙個ffffffff了。
在上面提到組合語言中符號擴充套件的問題,其實在c語言中屬於資料型別轉換的範疇。下面簡要說明一下:
符號擴充套件只針對將字長小的資料賦給字長大的資料時存在,若是字長大的資料賦給字長小的資料,取低位即可。
下面看一段程式:
#includeint main(void)
執行結果為:
-1原因是由於ch1、ch2、ch3都是char型變數,只佔乙個位元組,區別在於ch1是無符號的,在將ch1賦值給a時,ch1是看做無符號資料進行處理的,那麼在填充a的高位是用0去填充;而對於ch2和ch3都是有符號的,那麼在填充高位時就要注意了,若ch2的最高位為0,那麼表示ch2是正數,此時填充高位用0填充,而若ch2的最高位為1,則填充高位資料用1填充。
如程式執行的結果所示,由於ch2的最高位為1,那麼在填充b的高位的時候會用1去填充,那麼b為0x ff ff ff ff;而ch3的最高位為0,那麼填充c的高位用0填充,所以c的值為0x 00 00 00 73.
C語言檔案操作解析 五 之EOF解析
c語言檔案操作解析 五 之eof解析 在c語言中,有個符號大家都應該很熟悉,那就是eof end of file 即檔案結束符。但是很多時候對這個理解並不是很清楚,導致在寫 的時候經常出錯,特別是在判斷檔案是否到達檔案末尾時,常常出錯。1.eof是什麼?在vc中檢視eof的定義可知 define e...
C語言檔案操作解析 四
在檔案操作中除了開啟操作以及讀寫操作,還有幾種比較常見的操作。下面介紹一下這些操作中涉及到的函式。一.移動位置指標的函式 rewind函式和fseek函式,這兩個函式的原型是 void rewind file fp 將位置指標移動到檔案首 int fseek file fp,long int off...
C語言檔案操作解析 一
c語言檔案操作解析 一 在討論c語言檔案操作之前,先了解一下與檔案相關的東西。一.文字檔案和二進位制檔案 文字檔案的定義 由若干行字元構成的計算機檔案,存在於計算機系統中。文字檔案只能儲存檔案中的有效字元資訊,不能儲存影象 聲音等資訊。狹義上的二進位制檔案則指除開文字檔案之外的檔案,如 doc文件。...