这是错误的,因为(在没有读取错误的情况下)它进入循环的次数比作者预期的多一次。如果出现读取错误,则循环永远不会终止。
考虑以下代码:
/* 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()
在读取任何数据之前调用它,因此它返回 false。循环进入,fgetc()
被调用(并返回EOF
),并且计数增加。然后feof()
调用并返回 true,导致循环中止。
在所有此类情况下都会发生这种情况。 直到对流的读取遇到文件结尾之后feof()
才会返回 true 。的目的不是检查下一次读取是否会到达文件末尾。的目的是确定先前读取函数的状态,并区分错误情况和数据流结束。如果返回 0,则必须使用/来确定是否发生错误或是否消耗了所有数据。同样,如果返回。 仅在fread 返回零或返回后才有用。在此之前,将始终返回 0。feof()
feof()
fread()
feof
ferror
fgetc
EOF
feof()
fgetc
EOF
feof()
在调用 之前,总是需要检查读取的返回值(anfread()
或 anfscanf()
或 an ) 。fgetc()
feof()
更糟糕的是,考虑发生读取错误的情况。在这种情况下,fgetc()
返回EOF
,feof()
返回 false,并且循环永远不会终止。在所有使用的情况下while(!feof(p))
,必须至少在循环内检查 for ferror()
,或者至少应该将 while 条件替换为while(!feof(p) && !ferror(p))
或者存在无限循环的非常真实的可能性,可能会喷出各种垃圾作为正在处理无效数据。
所以,总而言之,虽然我不能肯定地说,永远不会有这样的情况,在这种情况下,写“ while(!feof(f))
”在语义上是正确的(尽管必须在循环内进行另一次检查,并用中断来避免读取错误时的无限循环),几乎可以肯定它总是错误的。即使出现了一个正确的案例,它也是惯用的错误,以至于它不是编写代码的正确方法。任何看到该代码的人都应该立即犹豫并说,“这是一个错误”。并且可能打作者(除非作者是你的老板,在这种情况下建议谨慎。)