Это противоречие между libc ++ и libstdc ++ - PullRequest
8 голосов
/ 25 января 2012

Следующая (игрушечная) программа возвращает разные вещи при связывании с libstdc ++ и libc ++.Это ошибка в libc ++ или я не понимаю, как работает istream eof ()?Я попытался запустить его с помощью g ++ на Linux и Mac OS X и Clang на Mac OS X, с и без -std = c ++ 0xУ меня сложилось впечатление, что eof () не возвращает true, пока попытка чтения (через get () или что-то еще) действительно не удалась.Вот как ведет себя libstdc ++, но не то, как ведет себя libc ++.

#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

Ответы [ 4 ]

5 голосов
/ 25 января 2012

РЕДАКТИРОВАТЬ : Это происходило из-за того, как старые версии libc ++ интерпретировали стандарт C ++.Интерпретация обсуждалась в выпуск LWG 2036 , она была признана неверной и libc ++ была изменена.

Текущий libc ++ дает в вашем тесте те же результаты, что и libstdc ++.

старый ответ:

Ваше понимание верно.

istream::get() выполняет следующее:

  1. Вызывает good() и устанавливает failbit, если возвращается false(это добавляет бит в поток, в котором был установлен какой-то другой бит), (§27.7.2.1.2[istream::sentry]/2)
  2. Сбрасывает все, что связано (), если необходимо,
  3. Если good() является ложным в этомpoint, возвращает eof и больше ничего не делает.
  4. Извлекает символ , как если бы , вызывая rdbuf()->sbumpc() или rdbuf()->sgetc() (§27.7.2.1[istream]/2)
  5. Если sbumpc()или sgetc() возвращает eof, устанавливает eofbit.(§27.7.2.1[istream]/3) и failbit (§27.7.2.2.3[istream.unformatted]/4)
  6. Если было сгенерировано исключение, устанавливает badbit (§27.7.2.2.3[istream.unformatted]/1) и сбрасывает, если это разрешено.
  7. Обновляет gcount и возвращает символ(или eof, если это не могло быть получено).

(главы цитируются из C ++ 11, но C ++ 03 имеет все те же правила, согласно § 27.6. *)

Теперь давайте взглянем на реализации:

libc ++ (текущая версия SVN) определяет соответствующую часть get () как

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 ++ (поставляется с gcc 4.6.2) определяет ту же часть, что и

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;

Как видите, обе библиотеки вызывают sbumpc() и устанавливают eofbit тогда и только тогда, когда sbumpc () возвращает eof.

Ваш тестовый сценарий выдает мне тот же вывод, используя последние версии обеих библиотек.

4 голосов
/ 26 января 2012

Это была ошибка libc ++, и она была исправлена, как заметил Cubbi. Виноват. Подробности здесь:

http://lwg.github.io/issues/lwg-closed.html#2036

1 голос
/ 25 января 2012

Значение s.eof() не указано во втором вызове - это может быть правда или ложь, и это может даже не быть последовательным. Все, что вы можете сказать, это что если s.eof() вернет true, все будущие входные данные потерпят неудачу (но если это возвращает false, нет гарантии, что будущие входные данные будут успешными). После сбоя (s.fail()), если s.eof() вернет true, вероятно (но не уверен на 100%) что ошибка произошла из-за конца файла. Это стоит однако, учитывая следующий сценарий:

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;

На моей машине обе строки "TT", несмотря на то, что первая не удалось, потому что не было данных (конец файла), второй, потому что Значение с плавающей точкой было неправильно отформатировано.

0 голосов
/ 25 января 2012

eofbit устанавливается, когда есть операция, которая пытается прочитать после конца файла, операция может не завершиться ошибкой (если вы читаете целое число, и после целого числа нет конца строки, я ожидаю, что eofbit будет установленно чтение целого числа для успеха).IE я получаю и ожидаю FT для

#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;
}

Здесь я не ожидаю, что istream :: get попытается прочитать после возвращенного символа (т.е. я не ожидаю, что он зависнет, пока не войду в следующую строкуесли я прочитал \ n с ним), то libstd ++ кажется действительно правильным, по крайней мере, в QOI POV.

Стандартное описание для istream :: get просто говорит "извлекает символ c, если он доступен"без описания того, как и как это не мешает поведению libc ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...