2012-09-09 18 views

Respuesta

27

Cada secuencia FILE tiene una marca interna que indica si la persona que llama ha intentado leer más allá del final del archivo. feof devuelve esa bandera. El indicador no indica si la posición actual del archivo es como el final del archivo, solo si una lectura previa ha intentado leer más allá del final del archivo.

Como ejemplo, veamos lo que sucede cuando leemos un archivo que contiene dos bytes.

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 

Esta es la razón por la que sigue es la mal manera de utilizar EF cuando se lee a través de un archivo:

f = fopen(filename, "r"); 
while (!feof(f)) { 
    c = getc(f); 
    putchar(c); 
} 

debido a la forma feof obras, el indicador de fin de archivo es de sólo establecer una vez getc intenta leer más allá del final del archivo. getc devolverá EOF, que es , no un carácter, y la construcción del bucle hace que putchar intente escribirlo , lo que da como resultado un error o una salida de basura.

método de entrada de la biblioteca estándar C Cada devuelve una indicación de éxito o fracaso : getc devuelve el valor especial EOF si se trató de leer más allá del final del archivo , o si hubo un error durante la lectura. El valor especial es , el mismo para fin de archivo y error, y aquí es donde entra la forma correcta de usar feof: puede usarlo para distinguir entre situaciones de fin de archivo y error .

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"); 
} 

Hay otro indicador interno para FILE objetos para situaciones de error: ferror. A menudo es más claro probar los errores en lugar de "no al final del archivo". Una forma idiomática para leer un archivo en C es la siguiente:

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

(comprobación de errores se ha eludido a partir de ejemplos aquí, por razones de brevedad.)

La función feof es bastante rara vez son útiles.

+2

Simple y correcto :-) – cnicutar

+1

Lo siento, me emocioné y lo amplié un poco. –

+0

Es aún mejor – cnicutar

3

Puede obtener una mejor comprensión de cómo funciona feof, al saber cómo se implementa. Aquí hay una versión simplificada de cómo la biblioteca de 7th Edition Unix stdio implementa feof. Las bibliotecas modernas son muy similares, agregando código que ofrece seguridad de subprocesos, mayor eficacia y una implementación más limpia.

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); 

}

La biblioteca stdio mantiene con cada archivo de una estructura que contiene un buffer interno señalado por _base.El carácter actual en el búfer está apuntado por _ptr y la cantidad de caracteres disponibles está en _cnt. La macro getc, que es la base de una gran cantidad de funcionalidades de nivel superior, como scanf, intenta devolver un carácter desde el búfer. Si el buffer está vacío, llamará al _filbuf para llenarlo. _filbuf a su vez llamará al read. Si read devuelve 0, lo que significa que no hay más datos disponibles, _filbuf configurará el indicador _IOEOF, que feof comprueba cada vez que lo llame para devolver verdadero.

Como usted puede entender de lo anterior, feof devolverá verdadero la primera vez que intente leer un carácter más allá del final del archivo (o una función de la biblioteca intenta en su nombre). Esto tiene implicaciones sutiles en el comportamiento de varias funciones. Considere un archivo que contiene un solo carácter: el dígito 1. Después de leer ese carácter con getc, feof devolverá falso, porque el indicador _IOEOF está desactivado; nadie ha intentado leer más allá del final del archivo. Llamar de nuevo al getc dará como resultado una llamada al read, la configuración del indicador _IOEOF, y esto hará que feof devuelva verdadero. Sin embargo, después de leer el número del mismo archivo usando fscanf("%d", &n), feof devolverá inmediatamente verdadero, porque fscanf habrá intentado leer dígitos adicionales del entero.