읽기 오류가 없으면 작성자가 예상 한 것보다 한 번 더 루프에 들어가기 때문에 잘못되었습니다. 읽기 오류가 있으면 루프가 종료되지 않습니다.
다음 코드를 고려하십시오.
/* 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;
}
이 프로그램은 입력 스트림의 문자 수보다 1을 크게 인쇄합니다 (읽기 오류가 없다고 가정). 입력 스트림이 비어있는 경우를 고려하십시오.
$ ./a.out < /dev/null
Number of characters read: 1
이 경우 feof()
데이터를 읽기 전에 호출되므로 false를 반환합니다. 루프가 입력되고을 fgetc()
호출 (및 반환 EOF
)하며 카운트가 증가합니다. 그런 다음 feof()
호출되어 true를 반환하여 루프가 중단됩니다.
이것은 모든 경우에 발생합니다. feof()
때까지 true를 반환하지 않습니다 후 스트림의 읽기는 파일의 끝을 발견. 목적은 feof()
다음 읽기가 파일의 끝에 도달하는지 확인하지 않는 것입니다. feof()
읽기 오류와 파일 끝에 도달 한 것을 구별 하는 것이 목적입니다 . 경우 fread()
0을 반환, 당신은 사용해야합니다 feof
/ ferror
오류가 발생했습니다 또는 모든 데이터가 소모 된 경우 여부를 결정합니다. 마찬가지로 if를 fgetc
반환합니다 EOF
. fread가 0 을 반환 하거나 반환 한 후에feof()
만 유용합니다 . 그 전에 항상 0을 반환합니다.fgetc
EOF
feof()
호출하기 전에 항상 읽기의 반환 값 ( fread()
, 또는 fscanf()
, 또는 fgetc()
)을 확인해야 feof()
합니다.
더 나쁜 것은 읽기 오류가 발생하는 경우를 고려하십시오. 이 경우, fgetc()
반환 EOF
, feof()
false를 반환하고, 루프는 종료하지 않습니다. while(!feof(p))
사용되는 모든 경우 에 대해 적어도 루프 내부에 대한 점검이 ferror()
있거나 최소한 while 조건이 대체되어야 while(!feof(p) && !ferror(p))
하거나 무한 루프의 실제 가능성이있을 수 있습니다. 유효하지 않은 데이터가 처리되고 있습니다.
따라서 요약하자면, " while(!feof(f))
"라고 쓰는 것이 의미 론적으로 올바른 상황은 없다고 확신 할 수는 없지만 ( 읽기 오류에서 무한 루프를 피하기 위해 중단으로 루프 내부에 다른 검사 가 있어야 하지만) ), 거의 항상 틀린 경우입니다. 그리고 올바른 경우가 발생하더라도 관용적으로 잘못되어 코드를 작성하는 올바른 방법이 아닐 수 있습니다. 이 코드를 보는 사람은 즉시 주저하고 "버그입니다"라고 말합니다. 저자가 당신의 상사 인 경우를 제외하고 저자를 때릴 수 있습니다.
feof()
루프를 제어 하기 위해 사용 하는 것이 나쁜 이유