feof กับ ferror
function ที่ใช้อ่าน file ใน standard library ของภาษา C มีอยู่ด้วยกันหลาย function
แต่ function เหล่านี้จะไม่สามารถแยกความแตกต่างระหว่าง end-of-file กับการเกิด error ได้
ตัวอย่างของ function เหล่านี้คือ

int fgetc (FILE *stream);
int getc (FILE *stream);
int getchar (void);

จะ return EOF เมื่อเจอ end-of-file หรือเมื่อเกิด error

char *fgets (char *s, int n, FILE *stream);
char *gets (char *s);

จะ return NULL เมื่อเจอ end-of-file หรือเมื่อเกิด error

int fscanf (FILE *stream, char *format, ... );
int scanf (char *format, ... );

จะ return EOF เมื่อเจอ end-of-file หรือเมื่อเกิด error

size_t fread (void *ptr, size_t size, size_t nitems, FILE *stream);
จะ return ค่าไม่เท่ากับ nitems เมื่อเจอ end-of-file หรือเมื่อเกิด error

การที่จะแยกให้ได้ว่าเกิด end-of-file หรือเกิด error ต้องใช้ feof กับ ferror ครับ
int feof (FILE *stream);
int ferror (FILE *stream);


เมื่อเกิด error ในการอ่าน FILE *stream
การเรียกใช้ ferror (stream) จะ return ค่าเป็น non-zero
ทำนองเดียวกัน เมื่ออ่าน FILE *stream จนเจอ end-of-file
การเรียกใช้ feof (FILE *stream) จะ return ค่าเป็น non-zero
function ทั้งสองจะมีลักษณะเหมือนกันคือ
ต้องเกิด เหตุ ขึ้นเสียก่อน แล้วถึงจะทดสอบเจอ
หาก เหตุไม่เกิด ก็ทดสอบไม่เจอ

สำหรับ ferror คงไม่ค่อยมีปัญหา (อาจเป็นเพราะไม่ค่อยเห็นใช้กัน)
แต่ feof นี่ผมเห็นใช้ผิดกันบ่อยๆ
เพราะว่ามันต้องอ่านจนเจอ end-of-file ถึงจะใช้ feof ทดสอบได้
แต่ที่เห็นใช้กันผิด คือไปทดสอบ feof ก่อน แล้วค่อยไปอ่าน stream เช่น

   while (!feof(fp)) {
      c = getc(fp);
      putchar(c);
   }


เพราะว่าถึงอ่าน byte สุดท้ายของ file ไปแล้ว คืออยู่ที่ท้าย file ไม่มีข้อมูลแล้ว
แต่ว่าตัว library function มันยังไม่รู้นะครับว่าไม่มีข้อมูลแล้ว
เราต้องสั่งให้อ่านต่อไป มันถึงจะรู้ว่าไม่มีข้อมูลแล้ว เจอ end-of-file แล้ว
feof ถึงจะทดสอบเจอ

มาทดสอบกันโดยสร้าง file ที่มีหนึ่งตัวอักษร
แล้วลองอ่าน file โดยใช้โปรแกรมที่ผิดแบบข้างบน
เปรียบเทียบกับโปรแกรมที่เขียนถูก

#include <stdio.h>
#define TEST_FILE "test.dat"

int main ()
{
   int c;
   FILE *fp;

   puts("Create file contains one character");
   fp = fopen(TEST_FILE, "w");
   if (fp == NULL) {
      perror("fopen w");
      return -1;
   }
   putc('A',fp);
   fclose(fp);

   puts("Bad feof program");
   fp = fopen(TEST_FILE, "r");
   if (fp == NULL) {
      perror("fopen r");
      return -1;
   }
   while (!feof(fp)) {
      c = getc(fp);
      printf("%c(%d)\n", c, c);
   }
   fclose(fp);

   puts("Good program");
   fp = fopen(TEST_FILE, "r");
   if (fp == NULL) {
      perror("fopen r");
      return -1;
   }
   while ((c = getc(fp)) != EOF)
      printf("%c(%d)\n", c, c);
   fclose(fp);

   puts("End");
   getchar();
   return 0;
}


ผลลัพธ์ที่ได้คือ
Create file contains one character
Bad feof program
A(65)
(-1)
Good program
A(65)
End


จะเห็นว่า feof จะทดสอบไม่เจอ end-of-file มันเลยอ่านเกินไปตัวนึง

แล้วควรใช้งาน feof ยังไง
คำตอบคือ ให้ใช้เท่าที่จำเป็น

จะเห็นว่าในโปรแกรมทดสอบอันที่ถูกของผม ไม่ใช้ feof ด้วยซ้ำ
เพราะมันไม่จำเป็นต้องใช้
ที่ผิดกันบ่อยคือใช้ feof เป็น loop condition
ทั้งที่จริงๆเราก็ loop อ่านจนมันอ่านไม่ได้แหละครับ
ไม่ว่าจะอ่านไม่ได้เพราะ end-of-file หรือ error
ไม่เห็นต้องใช้ feof เลย
หลังออกจาก loop แล้วถ้าอยากรู้ว่า error หรือเปล่าค่อยไปใช้ ferror เช่น

   while ((c = getc(fp)) != EOF)
      printf("%c(%d)\n", c, c);
   if (ferror(fp))
      perror("getc");






สรุปว่าใช้แบบพอเพียงครับ







Create Date : 12 กันยายน 2552
Last Update : 12 กันยายน 2552 21:27:08 น.
Counter : 3517 Pageviews.

5 comments
  
สวัสดีครับ ขอบคุณสำหรับความรู้ดี ๆ ครับ ช่วงนี้ไม่ค่อยได้ใช้ภาษาซี ใช้แต่ Java เป็นหลัก ได้เข้ามาอ่านก็ดหมือนได้ทบทวนภาษาซีไปในตัว
โดย: motokop วันที่: 10 ตุลาคม 2552 เวลา:22:38:44 น.
  
สวัสดีครับ มาทักทายกันวันศุกร์ แต่ต่อไปสงสัยจะได้ทักทายกันทาง twitter อีกทางหนึ่งด้วย
โดย: motokop วันที่: 16 ตุลาคม 2552 เวลา:20:30:29 น.
  
ขอให้มีร่างกายและจิตใจที่พร้อมสำหรับปีใหม่ที่จะมาถึงนะครับ

คลิกๆๆ รูปสวยๆน่ารักๆไว้ส่งต่อเพียบ...
โดย: motokop วันที่: 31 ธันวาคม 2552 เวลา:14:37:12 น.
  
สุขสันต์วันสงกรานต์ครับ

คลิกๆๆ รูปสวยๆน่ารักๆไว้ส่งต่อเพียบ...
โดย: motokop วันที่: 13 เมษายน 2553 เวลา:23:16:48 น.
  
ถ้าต้องใช้ feof จริงๆ
ต้องใช้ยังไงดีครับ
โดย: prikthai IP: 202.12.74.1 วันที่: 14 มกราคม 2554 เวลา:18:19:14 น.
ชื่อ :
Comment :
 *ใช้ code html ตกแต่งข้อความได้เฉพาะสมาชิก
 

Zkaru.BlogGang.com

zkaru
Location :
กรุงเทพฯ  Thailand

[ดู Profile ทั้งหมด]
 ผู้ติดตามบล็อก : 2 คน [?]