2012-09-09 3 views

답변

27

모든 FILE 스트림에는 호출자가 이미 파일 끝을지나 읽으려고했는지 여부를 나타내는 내부 플래그가 있습니다. feof은 해당 플래그를 반환합니다. 이 플래그는 현재 파일 위치가 파일의 끝인지 여부를 나타내지 않고 이전 읽기가 파일 끝을지나 읽으려고했는지 여부 만 나타냅니다.

예를 들어, 2 바이트를 포함하는 파일을 읽을 때 어떤 일이 발생하는지 살펴 보겠습니다.

방식 때문에 feof 작품의
f = fopen(filename, "r"); 
while (!feof(f)) { 
    c = getc(f); 
    putchar(c); 
} 

는 파일 끝 플래그는 다음과 같습니다 다음 파일을 읽을 때 EOF를 사용하는 잘못된 방법은 왜

f = fopen(filename, "r"); // file is opened 
assert(!feof(f));   // eof flag is not set 
c1 = getc(f);    // read first byte, one byte remaining 
assert(!feof(f));   // eof flag is not set 
c2 = getc(f);    // read second byte, no bytes remaining 
assert(!feof(f));   // eof flag is not set 
c3 = getc(f);    // try to read past end of the file 
assert(feof(f));   // now, eof flag is set 

이입니다 한 번 설정하십시오 getc 은 파일의 끝을 지나서 읽으려고합니다. getc은 문자가 아닌 인 EOF을 반환하고 putchar은 루프를 작성하면 을 쓰려고 시도하여 오류 또는 가비지 출력이 발생합니다. 이 파일의 끝을지나 읽기를 시도하는 경우, 또는 에러가 발생했을 경우 읽는 동안 특수 값 EOF을 반환 getc :

모든 C 표준 라이브러리 입력 방법은 성공 또는 실패의 표시를 반환합니다. 특수 값은 파일 끝과 오류에 대해 동일하게 이며, 여기에서 feof을 사용하는 적절한 방법이 있습니다. 파일 끝과 오류 상황을 구별하는 데이 값을 사용할 수 있습니다. ferror :

f = fopen(filename, "r"); 
c = getc(f); 
if (c == EOF) { 
    if (feof(f)) 
     printf("it was end-of-file\n"); 
    else 
     printf("it was error\n"); 
} 

오류 상황에 대한 FILE 객체에 대한 또 다른 내부 플래그가있다. "파일 끝이 아니라"대신 오류를 테스트하는 것이 더 명확합니다. C에서 파일을 읽을 수 관용적 방법은 다음과 같이이다 :

f = fopen(filename, "r"); 
while ((c = getc(f)) != EOF) { 
    putchar(c); 
} 
if (ferror(f)) { 
    perror(filename): 
    exit(EXIT_FAILURE); 
} 
fclose(f); 

(일부 오류 검사를 간결, 여기 예에서 생략되었습니다.)

feof 기능은 매우 드물게 유용합니다.

+2

간단하고 정확 :-) – cnicutar

+1

죄송합니다. 흥분하고 조금 확장했습니다. –

+0

더 나아졌습니다. – cnicutar

3

구현 방법을 알면 feof의 작동 방식을 더 잘 이해할 수 있습니다. 다음은 7th Edition Unix stdio 라이브러리가 feof을 어떻게 구현하는지 단순화 된 버전입니다. 현대 라이브러리는 스레드 안전성, 효율성 향상 및보다 명확한 구현을 제공하는 코드를 추가하는 것과 매우 유사합니다.

extern struct _iobuf { 
    char *_ptr; 
    int  _cnt; 
    char *_base; 
    char _flag; 
    char _file; 
} _iob[_NFILE]; 

#define _IOEOF 020 

#define feof(p)   (((p)->_flag&_IOEOF)!=0) 

#define getc(p)   (--(p)->_cnt>=0? *(p)->_ptr++&0377:_filbuf(p)) 

int 
_filbuf(FILE *iop) 
{ 

    iop->_ptr = iop->_base; 
    iop->_cnt = read(fileno(iop), iop->_ptr, BUFSIZ); 
    if (iop->_cnt == 0) { 
      iop->_flag |= _IOEOF; 
      return(EOF); 
    } 
    return(*iop->_ptr++ & 0377); 

}

STDIO 라이브러리는 각 파일 _base 가리키는 내부 버퍼를 포함하는 구조를 유지한다.버퍼의 현재 문자는 _ptr이며, 사용 가능한 문자 수는 _cnt입니다. scanf과 같이 많은 상위 수준 기능의 기반이되는 getc 매크로는 버퍼에서 문자를 반환하려고 시도합니다. 버퍼가 비어 있으면 _filbuf을 호출하여 버퍼를 채 웁니다. _filbufread으로 전화 할 것입니다. read이 0을 반환하면 더 이상 사용할 수있는 데이터가 없음을 의미하고 _filbuf_IOEOF 플래그를 설정합니다. feof은 true를 반환 할 때마다이 값을 검사합니다.

위의 내용에서 알 수 있듯이 feof은 파일 끝에 도달 한 문자를 처음 읽으려고하면 (또는 라이브러리 함수가 사용자를 대신하여 시도 할 때) true를 반환합니다. 이것은 다양한 기능의 동작에 미묘한 영향을 미칩니다. 단일 문자를 포함하는 파일을 고려하십시오 : 숫자 1. getc으로 해당 문자를 읽은 후 _IOEOF 플래그가 설정되어 있지 않으므로 feof은 false를 반환합니다. 아무도 아직 파일의 끝을 읽으려고 시도하지 않았습니다. getc을 다시 호출하면 _IOEOF 플래그가 설정되어 read으로 호출되며 이로 인해 feof이 true를 반환합니다. 그러나 fscanf("%d", &n)을 사용하여 같은 파일에서 번호를 읽은 후 fscanf은 정수의 추가 숫자를 읽으려고 시도하기 때문에 feof은 즉시 true를 반환합니다.

관련 문제