มันผิดเพราะ (ในกรณีที่ไม่มีข้อผิดพลาดในการอ่าน) มันจะเข้าสู่ลูปมากกว่าหนึ่งครั้งที่ผู้เขียนคาดไว้ หากมีข้อผิดพลาดในการอ่านลูปจะไม่สิ้นสุด
พิจารณารหัสต่อไปนี้:
/* WARNING: demonstration of bad coding technique!! */
#include <stdio.h>
#include <stdlib.h>
FILE *Fopen(const char *path, const char *mode);
int main(int argc, char **argv)
{
FILE *in;
unsigned count;
in = argc > 1 ? Fopen(argv[1], "r") : stdin;
count = 0;
/* WARNING: this is a bug */
while( !feof(in) ) { /* This is WRONG! */
fgetc(in);
count++;
}
printf("Number of characters read: %u\n", count);
return EXIT_SUCCESS;
}
FILE * Fopen(const char *path, const char *mode)
{
FILE *f = fopen(path, mode);
if( f == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return f;
}
โปรแกรมนี้จะพิมพ์หนึ่งตัวอักษรมากกว่าจำนวนอักขระในอินพุตสตรีมอย่างต่อเนื่อง (สมมติว่าไม่มีข้อผิดพลาดในการอ่าน) พิจารณากรณีที่สตรีมอินพุตว่าง:
$ ./a.out < /dev/null
Number of characters read: 1
ในกรณีนี้feof()
จะถูกเรียกใช้ก่อนที่จะอ่านข้อมูลใด ๆ ดังนั้นจึงส่งคืนค่าเท็จ ลูปถูกป้อนfgetc()
เรียกว่า (และส่งคืนEOF
) และจำนวนจะเพิ่มขึ้น จากนั้นfeof()
จะถูกเรียกใช้และส่งกลับค่าจริงทำให้ลูปยกเลิก
สิ่งนี้เกิดขึ้นในทุกกรณี feof()
ไม่ส่งคืนจริงจนกว่าหลังจากที่อ่านบนสตรีมพบจุดสิ้นสุดของไฟล์ วัตถุประสงค์ของการfeof()
ไม่ตรวจสอบว่าการอ่านครั้งต่อไปจะมาถึงจุดสิ้นสุดของไฟล์หรือไม่ วัตถุประสงค์feof()
คือเพื่อแยกความแตกต่างระหว่างข้อผิดพลาดในการอ่านและถึงจุดสิ้นสุดของไฟล์ หากfread()
ส่งคืน 0 คุณต้องใช้feof
/ ferror
เพื่อตัดสินใจว่าจะเกิดข้อผิดพลาดหรือข้อมูลทั้งหมดถูกใช้ไปแล้ว ในทำนองเดียวกันถ้าผลตอบแทน fgetc
มีประโยชน์เฉพาะหลังจากที่ fread คืนค่าศูนย์หรือคืนค่าแล้ว ก่อนที่จะเกิดขึ้นEOF
feof()
fgetc
EOF
feof()
จะส่งคืน 0 เสมอ
จำเป็นต้องตรวจสอบค่าส่งคืนของการอ่าน (อย่างใดอย่างหนึ่งfread()
หรือfscanf()
หรือfgetc()
) ก่อนที่จะโทรfeof()
ก่อนที่จะเรียก
ยิ่งแย่กว่านั้นให้พิจารณากรณีที่เกิดข้อผิดพลาดในการอ่าน ในกรณีที่, fgetc()
ผลตอบแทนEOF
, feof()
ผลตอบแทนเท็จและห่วงไม่เคยสิ้นสุด ในทุกกรณีที่while(!feof(p))
มีการใช้งานจะต้องมีการตรวจสอบภายในลูปสำหรับferror()
อย่างน้อยที่สุดหรืออย่างน้อยที่สุดควรจะแทนที่ด้วยเงื่อนไข while while(!feof(p) && !ferror(p))
หรือมีความเป็นไปได้ที่แท้จริงของลูปที่ไม่สิ้นสุดซึ่งอาจทำให้ขยะทุกประเภทเป็น กำลังประมวลผลข้อมูลที่ไม่ถูกต้อง
ดังนั้นโดยสรุปแม้ว่าฉันไม่สามารถระบุด้วยความมั่นใจได้ว่าจะไม่มีสถานการณ์ที่อาจจะถูกต้องในการเขียน " while(!feof(f))
" (แม้ว่าจะต้องมีการตรวจสอบอีกครั้งภายในลูปพร้อมกับตัวแบ่งเพื่อหลีกเลี่ยงการวนซ้ำไม่สิ้นสุดในข้อผิดพลาดการอ่าน ) เป็นกรณีที่เกือบผิดเสมอ และแม้ว่ากรณีจะเกิดขึ้นที่ใดก็ตามที่มันถูกต้องมันเป็นเรื่องผิดปกติที่ไม่น่าจะเป็นวิธีที่ถูกต้องในการเขียนรหัส ใครก็ตามที่เห็นรหัสนั้นควรลังเลทันทีและพูดว่า "นั่นเป็นข้อผิดพลาด" และอาจตบผู้เขียน (เว้นแต่ผู้แต่งคือหัวหน้าของคุณในกรณีที่แนะนำให้ใช้ดุลยพินิจ)
feof()
ในการควบคุมวง