2012-02-08 13 views
9

Este código recorre siempre:¿Cuándo `ifstream :: readsome` establece` eofbit`?

#include <iostream> 
#include <fstream> 
#include <sstream> 

int main(int argc, char *argv[]) 
{ 
    std::ifstream f(argv[1]); 
    std::ostringstream ostr; 

    while(f && !f.eof()) 
    { 
     char b[5000]; 
     std::size_t read = f.readsome(b, sizeof b); 
     std::cerr << "Read: " << read << " bytes" << std::endl; 
     ostr.write(b, read); 
    } 
} 

Es porque se readsome configuración Nunca eofbit.

cplusplus.com dice:

errores se señalizan mediante la modificación de las banderas de estado internas:

eofbit La conseguir puntero se encuentra al final del interno matriz de entrada del búfer de la secuencia cuando se invoca la función, significado que no hay posiciones para ser leer en el búfer interno (que puede ser o no el final de la secuencia de entrada ). Esto ocurre cuando rdbuf()->in_avail() devolvería -1 antes de que se extraiga el primer carácter .

failbit La secuencia estaba al final de la fuente de caracteres antes de llamar a la función .

badbit Se produjo un error diferente al anterior.

Casi la misma, el estándar dice:

[C++11: 27.7.2.3]:streamsize readsome(char_type* s, streamsize n);

32. Efectos: se comporta como una función de entrada sin formato (como se describe en 27.7.2.3, párrafo 1) . Después de construir un objeto centinela, si !good() llama al setstate(failbit), que puede generar una excepción y devolver. De lo contrario, extrae los caracteres y los almacena en ubicaciones sucesivas de una matriz cuyo primer elemento se designa con s. Si rdbuf()->in_avail() == -1, llama al setstate(eofbit) (que puede arrojar ios_base::failure (27.5.5.4)), y extrae sin caracteres;

  • Si rdbuf()->in_avail() == 0, extractos ningún carácter
  • If rdbuf()->in_avail() > 0, extractos min(rdbuf()->in_avail(),n)).

33. Devoluciones: Número de caracteres extraídos.

que la condición in_avail() == 0 es un no-op implica que ifstream::readsome sí mismo es un no-op si el búfer de la secuencia está vacía, pero la condición in_avail() == -1 implica que se establecer eofbit cuando alguna otra operación tiene llevado a in_avail() == -1.

Esto parece una incoherencia, incluso a pesar de la naturaleza "algo" de readsome.

Entonces, ¿qué son la semántica de readsome y eof? ¿Los he interpretado correctamente? ¿Son un ejemplo de diseño deficiente en la biblioteca de secuencias?


(robado de la [OMI] inválido libstdc++ bug 52169.)

Respuesta

4

Creo que este es un punto de personalización, realmente no utilizado por las implementaciones de flujo predeterminado.

in_avail() devuelve el número de caracteres que puede ver en el búfer interno, si corresponde. De lo contrario, llama al showmanyc() para tratar de detectar si se sabe que los caracteres están disponibles en otro lugar, por lo que se garantiza que una solicitud de relleno del búfer tendrá éxito.

A su vez, showmanyc() devolverá el número de caracteres que sabe acerca, en su caso, o -1 si sabe que una lectura va a fracasar, o 0 si no tiene ni idea.

La implementación por defecto (basic_streambuf) siempre devuelve 0, de modo que es lo que hay a menos que tenga una corriente con algún otro streambuf anulando showmanyc.

Su bucle es esencialmente read-as-many-chars-as-you-know-is-safe, y se atasca cuando es cero (lo que significa "no estoy seguro").

+0

Gracias; ¡eso ayuda! –

1

Si ningún carácter está disponible (es decir gptr() == egptr() para la std:streambuf) la función miembro virtual showhowmanyc() se llama. Podría tener una implementación de showmanyc() que devuelve un código de error. Por qué eso puede ser útil es una pregunta diferente. Sin embargo, esto podría establecer eof(). Por supuesto, in_avail() está destinado a no fallar y no bloquear y simplemente devolver los caracteres que se sabe están disponibles. Es decir, el ciclo que tienes arriba está garantizado esencialmente como un bucle infinito a menos que tengas un búfer de transmisión bastante extraño.

+0

Por qué eso puede ser útil es _esta pregunta :) –

0

No creo que readsome() es para lo que estamos tratando de hacer (leer de un archivo en el disco) ... del cplusplus.com:

La función está destinada a se utilizará para leer datos binarios de ciertos tipos de fuentes asincrónicas que pueden esperar a más caracteres, ya que deja de leer cuando se agota el búfer local, evitando posibles demoras inesperadas .

Parece que readsome() está destinado a las transmisiones desde un socket de red o algo así, y probablemente solo quiera usar read().

+0

En realidad, estoy leyendo un flujo NMEA desde un receptor GPS. Pero FWIW el código original no era mío; era de otra pregunta SO, y simplemente quería racionalizar sobre el comportamiento de '.readsome'; ya sea que sea apropiado para un archivo o no, espero que se configure 'eof' cuando se alcance el EOF. –

+0

Ah, está bien. Si la estructura del código sigue reflejando el fragmento anterior, aún sugeriría usar read() ... readsome() parece usar una semántica no bloqueante, lo que simplemente causaría un ciclo cerrado de "no hacer nada" cuando no haya ingresado ningún dato Solo para aclarar: ¿este código todavía no hace nada cuando el socket está cerrado? – bdow

+0

Tienes razón, ese es el comportamiento de 'readsome()'.Esta pregunta se trata de racionalizar sobre ese comportamiento, independientemente de cualquier uso particular. Y no estoy seguro de qué sucede cuando el socket está cerrado ya que no tengo el testcase original ejecutándose en ningún lado. –