2012-01-25 14 views
8

Il seguente programma (giocattolo) restituisce cose diverse quando è collegato a libstdC++ e libC++. Si tratta di un bug in libC++ o non capisco come funziona isream eof()? Ho provato a farlo usando g ++ su linux e mac os x e clang su mac os x, con e senza -std = C++ 0x. Ho avuto l'impressione che eof() non restituisca true fino a quando un tentativo di lettura (di get() o qualcos'altro) fallisce. Ecco come si comporta libstdC++, ma non come si comporta libC++.discrepanza di istream eof tra libC++ e libstdC++

#include <iostream> 
#include <sstream> 

int main() { 
    std::stringstream s; 

    s << "a"; 

    std::cout << "EOF? " << (s.eof() ? "T" : "F") << std::endl; 
    std::cout << "get: " << s.get() << std::endl; 
    std::cout << "EOF? " << (s.eof() ? "T" : "F") << std::endl; 

return 0; 
} 

Thor:~$ g++ test.cpp 
Thor:~$ ./a.out 
EOF? F 
get: 97 
EOF? F 
Thor:~$ clang++ -std=c++0x -stdlib=libstdc++ test.cpp 
Thor:~$ ./a.out 
EOF? F 
get: 97 
EOF? F 
Thor:~$ clang++ -std=c++0x -stdlib=libc++ test.cpp 
Thor:~$ ./a.out 
EOF? F 
get: 97 
EOF? T 
Thor:~$ clang++ -stdlib=libc++ test.cpp 
Thor:~$ ./a.out 
EOF? F 
get: 97 
EOF? T 

risposta

0

eofbit è impostato quando c'è un'operazione che tenta di leggere oltre la fine del file, l'operazione non può riuscire (se si sta leggendo un intero e non c'è fine della linea dopo il numero intero, mi aspetto eofbit da impostare ma la lettura dell'intero per avere successo). OSSIA Ottengo e aspetto FT per

#include <iostream> 
#include <sstream> 

int main() { 
    std::stringstream s("12"); 
    int i; 
    s >> i; 

    std::cout << (s.fail() ? "T" : "F") << (s.eof() ? "T" : "F") << std::endl; 

    return 0; 
} 

Qui non mi aspetto IStream :: la possibilità di provare e leggere dopo il carattere restituito (cioè non mi aspetto la sua sospensione fino a quando entro nella riga successiva se leggo a \ n con esso), quindi libstd ++ sembra davvero giusto, almeno in un POV QOI.

La descrizione standard per istream :: get dice semplicemente "estrae un carattere c, se uno è disponibile" senza descrivere come e così non sembra impedire il comportamento di libC++.

1

Il valore di s.eof() non è specificato nella seconda chiamata — potrebbe essere vero o falso e potrebbe non essere nemmeno coerente. Tutto quello che puoi dire è che se s.eof() restituisce true, tutti gli input futuri non funzioneranno (ma se restituisce false, non c'è alcuna garanzia che l'input futuro abbia esito positivo). Dopo un errore (s.fail()), se s.eof() restituisce true, è probabile (ma non è sicuro al 100%) che l'errore sia dovuto alla fine del file. Vale la pena considerare il seguente scenario, però:

double test; 
std::istringstream s1(""); 
s1 >> test; 
std::cout << (s1.fail() ? "T" : "F") << (s1.eof() ? "T" : "F") << endl; 
std::istringstream s2("1.e-"); 
s2 >> test; 
std::cout << (s2.fail() ? "T" : "F") << (s2.eof() ? "T" : "F") << endl; 

Sulla mia macchina, entrambe le linee sono "TT", nonostante il fatto che il primo fallito perché non c'era alcun dato (fine del file), il secondo perché il il valore in virgola mobile è stato formattato in modo errato.

+0

Come è specificato? Lo standard è chiaro: imposta failbit ed eofbit se sbumpc()/sgetc() restituisce eof, imposta badbit se viene lanciata un'eccezione. – Cubbi

+0

@Cubbi No. Imposta 'eofbit' se' sgetc' restituisce eof, ma non necessariamente 'failbit'; guardare avanti è sempre legale e talvolta necessario. E quando e quanto spesso esattamente 'get' chiama' sgetc' non è specificato. –

+0

Ho postato la risposta come risposta. – Cubbi

5

EDIT: Ciò era dovuto al modo in cui le versioni precedenti di libC++ interpretavano lo standard C++. L'interpretazione è stata discussa in LWG issue 2036, è stata dichiarata errata e libC++ è stata modificata.

Current libC++ fornisce gli stessi risultati del test di libstdC++.

risposta antiche:

La vostra comprensione è corretta.

istream::get() esegue le seguenti operazioni:

  1. chiede good(), e imposta failbit se restituisce false (questo aggiunge un failbit a un flusso che ha avuto qualche altro set bit), (§27.7.2.1.2[istream::sentry]/2)
  2. vampate di qualunque legame() 'd se necessario
  3. Se good() è falso a questo punto, restituisce eof e non fa nient'altro.
  4. Estrae un personaggio come se chiamando rdbuf()->sbumpc() o rdbuf()->sgetc() (§27.7.2.1[istream]/2)
  5. Se sbumpc() o sgetc() restituito EOF, imposta eofbit. (§27.7.2.1[istream]/3) e failbit (§27.7.2.2.3[istream.unformatted]/4)
  6. Se è stata generata un'eccezione, imposta badbit (§27.7.2.2.3[istream.unformatted]/1) e retrocede se consentito.
  7. Aggiorna account e restituisce il carattere (o ef se non è stato possibile ottenere).

(capitoli citato da C++ 11, ma C++ 03 ha tutte le stesse regole, in §27.6 *.)

Ora diamo uno sguardo alle implementazioni:

libC++ (versione corrente svn) definisce la parte rilevante del get() come

sentry __s(*this, true); 
if (__s) 
{ 
    __r = this->rdbuf()->sbumpc(); 
    if (traits_type::eq_int_type(__r, traits_type::eof())) 
     this->setstate(ios_base::failbit | ios_base::eofbit); 
    else 
     __gc_ = 1; 
} 

libstdC++ (come spedito con gcc 4.6.2) definisce la stessa parte di

sentry __cerb(*this, true); 
if (__cerb) 
    { 
    __try 
     { 
     __c = this->rdbuf()->sbumpc(); 
     // 27.6.1.1 paragraph 3 
     if (!traits_type::eq_int_type(__c, __eof)) 
      _M_gcount = 1; 
     else 
      __err |= ios_base::eofbit; 
     } 
[...] 
if (!_M_gcount) 
    __err |= ios_base::failbit; 

Come si può vedere, entrambe le librerie chiamano sbumpc() e impostare eofbit se e solo se sbumpc() ha restituito EOF.

tuo testcase produce la stessa uscita per me usando le versioni recenti di entrambe le librerie.

+0

Questo è strano. Non riesco a trovare alcun testo tra le tue citazioni nelle mie versioni dello standard (C++ 03 e N3291): entrambe le mie versioni dicono che 'get' " Funziona come una funzione di input non formattata.Dopo il la costruzione di una sentinella oggetto, estrae un carattere c, se uno è disponibile. " Niente sul numero di chiamate a 'rdbuf() -> sbump()' o 'rdbuf() -> sgetc()'. Anche se non ci si aspetterebbe, non c'è nulla di illegale un'implementazione che fa un ulteriore invito a 'rdbuf() -> sgetc()', e l'impostazione 'eofbit' a causa di questo. –

+0

Diversi punti sulla vostra lista di azioni in materia di: punto 2: 'istream :: get()' non fare questo --- è parte delle azioni della costruttore dell'oggetto 'sentry'. Per quanto riguarda i punti 3 e 4: lo standard è molto meno vincolante. Estrazione deve essere _as IF_ da chiamando 'rdbuf() -> sbumpc()' o 'rdbuf() -> sgetc()' (che è un errore, dal momento che 'rdbuf() -> sgetc()' non lo fa estrai, e 'rdbuf() -> snextc()' e 'rdbuf-> sgetn()', che fanno, non sono menzionati). Questo non dice nulla su quando e se si verifica il look-ahead. –

+0

@JamesKanze Per quanto riguarda la sentinella, le azioni del suo costruttore sono parte di ciò che fa "istream :: get()".Come qualsiasi cosa in C++, è come-se: l'implementazione può (ea volte fa) fare qualcosa di ciò che dovrebbe fare direttamente in 'get()'. Per quanto riguarda un'ulteriore chiamata a sgetc - non c'è nulla di illegale nel chiamarlo o in qualsiasi altra funzione, ma sarebbe illegale impostare eofbit a causa di ciò che è stato restituito perché violerebbe la clausola as-if. – Cubbi

Problemi correlati