Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
kravam
быдлокодер
1706 / 893 / 105
Регистрация: 04.06.2008
Сообщений: 5,524
#1

Почему если флаг состояния потока eof поднят, то флаг good опущен? - C++

19.10.2014, 21:28. Просмотров 862. Ответов 15
Метки нет (Все метки)

Почему если флаг состояния потока eof поднят, то флаг good опущен?

Это нонсенс, друзья.
Здесь прочтём, что флаг goodbit потока поднят, если опущены все флаги
http://www.cyberforum.ru/cpp-beginners/thread762705.html
eofbit, failbit and badbit

И тут же пониже, что флаг eof поднят, когда достигнут конец входного потока, то есть по-русски говоря, когда всё считалось OK

eofbit End-of-File reached on input operation.
То есть если всё хорошо читается до конца-> поднимается флаг eofbit-> опускается флаг good. А он вроде как должен быть ПОДНЯТ, если всё хорошо считалось, он же всё-таки good!

А вот код, подтверждающий это. Задействованы все флаги на всякий случай, чтобы было видно, что goodbit опущен только из-за одно поднятого eofbit

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <windows.h>
#include <stdio.h>
#include <sstream>
 
using namespace std;
 
int main()
{
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
      
 
     //////////////////
     //////////////////
     string str= "stroka";
     istringstream is (str);
     is>> str;
 
     if (is.fail())
      printf ("+fail\n");
     else
      printf ("-fail\n");
 
     if (is.eof())
      printf ("+eof\n");
     else
      printf ("-eof\n");
 
     if (is.good())
      printf ("+good\n");
     else
      printf ("-good\n");
     
     if (is.bad())
      printf ("+bad\n");
     else
      printf ("-bad\n");
 
 
    system("pause");
    return 0;
}
Вывод:
Bash
1
2
3
4
-fail
+eof
-good
-bad
Какие будут мнения по этому чёрному юмору разработчиков? Спасибо, кто откликнется.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.10.2014, 21:28
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Почему если флаг состояния потока eof поднят, то флаг good опущен? (C++):

Почему событие eof() файлового потока наступает очень поздно? Какова вообще его логика?
Вот пример, если в папке с программой разместить файл input.txt с числами &quot;1 2...

Флаг skipws
Как работает флаг cin.unsetf(ios::skipws), какие именно разделители он...

флаг сбрасывается
Всем доброго времени суток! Столкнулся с проблемой: пытаюсь сделать флаг, что...

Не реагирует на флаг
Всем привет есть такая задачка мой код #include&lt;iostream&gt;...

Флаг переполнения
Доброго времени суток! Подскажите, как проверить какую-либо определенную...

15
nmcf
6237 / 5549 / 2524
Регистрация: 14.04.2014
Сообщений: 23,331
19.10.2014, 21:34 #2
Потому что читать больше нечего из потока.
0
kravam
быдлокодер
1706 / 893 / 105
Регистрация: 04.06.2008
Сообщений: 5,524
19.10.2014, 21:38  [ТС] #3
И поэтому я должен думать, что прочитано плохо или неправильно или вообще не прочитано?
0
nmcf
6237 / 5549 / 2524
Регистрация: 14.04.2014
Сообщений: 23,331
19.10.2014, 21:43 #4
Для этого есть отдельные три флага. good - это для того, чтобы начинать или не начинать новую операцию, а не для анализа старой.
1
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4371 / 2346 / 654
Регистрация: 18.10.2014
Сообщений: 3,996
20.10.2014, 08:05 #5
В стандартных потоках флаг конца файла поднимается не тогда, когда указатель чтения просто тихонько "достиг конца файла", а тогда, когда вызывающий код предпримет попытку продвинуть его дальше, за конец файла. То есть флаг конца файла будет поднят тогда, когда конец файла фактически уже достигнут, а внешний код (который об этом еще не знает) тем не менее попытается выполнить попытку чтения данных из файла. Эта попытка будет, разумеется, неудачной. И вот только в этот момент в потоке будет поднят флаг 'eof'.

Таким образом, поднятие флага 'eof' - это всегда результат ошибочной ситуации - попытки чтения несуществующих данных за концом файла. Именно по этой причине ситуация 'eof' не считается 'good'.

Вот в таком коде, где входной поток состоит из одного единственного символа, флаг 'eof' после прочтения этого символа выставлен не будет. А появится он только после попытки прочтения второго, несуществующего символа.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
string str= "s";
istringstream is(str);
 
char c;
 
is >> c;
if (is.eof())
  printf ("+eof\n");
else
  printf ("-eof\n");
 
is >> c;
if (is.eof())
  printf ("+eof\n");
else
  printf ("-eof\n");
Когда выполняется чтение из потока разнообразных многосимвольных объектов (строк, чисел и т.п.), то будет выставлен флаг 'eof' или не будет зависит от того, по какой причине было прервано чтение символов из потока. Если оно было прервано из-за попытки чтения после конца файла, то в вызывающем коде вы увидите 'eof'. Если же чтение было прервано по какой-то другой причине, что в вызывающем коде вы не увидите 'eof', даже если фактически коней файла уже достигнут.

Например, в вашем примере вы читаете из потока строку неограниченной длины. Алгоритм чтения строки будет выдергивать из входного потока один символ за другим, пока не встретит пробел или конец файла. "Встретит конец файла" в данном случае означает именно "попытается прочитать несуществующий символ". Именно это и происходит в вашем примере. Оператор 'is >> str' успешно читает шесть символов (флага 'eof' после этого еще не возникает), а затем пытается прочитать седьмой. Это ему не удается и выставляется флаг 'eof'. Именно этот флаг вы и видите в вызывающем коде.

Однако если вы будете читать вашу строку вот так

C++
1
2
3
string str= "stroka";
istringstream is (str);
is >> setw(6) >> str;
то обнаружите, что никакого флага 'eof' при таком чтении не выставляется. Чтение было прекращено по причине достижения заданной длины. Попытки чтения седьмого символа не было и, соответственно, ситуация 'eof' обнаружена не была.
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
20.10.2014, 10:43 #6
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
то обнаружите, что никакого флага 'eof' при таком чтении не выставляется.
В gcc это не так:
http://coliru.stacked-crooked.com/a/3a4e7b2640cb899a
А вот в студии eof действительно не выставляется.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4371 / 2346 / 654
Регистрация: 18.10.2014
Сообщений: 3,996
20.10.2014, 11:14 #7
Это интересная деталь. Это, по-видимому, означает, что условие завершения чтения в gcc первым делом проверяет входной поток на пробельный символ и лишь потом проверяет ограничение на длину. Попытка проверки на пробельный символ (т.е. попытка чтения следующего символа) и выставляет eof.

Интересно, специфицирует ли стандарт языка порядок проверки условий завершения чтения.
0
notemac
27 / 27 / 18
Регистрация: 13.09.2014
Сообщений: 137
20.10.2014, 11:39 #8
А если через строку, то
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
char str = "stroka";
    istrstream is(str);
    is >> setw(6)>>str;
 
    if (is.fail())
        printf("+fail\n");
    else
        printf("-fail\n");
 
    if (is.eof())
        printf("+eof\n");
    else
        printf("-eof\n");
 
    if (is.good())
        printf("+good\n");
    else
        printf("-good\n");
 
    if (is.bad())
        printf("+bad\n");
    else
        printf("-bad\n");
    cout<<endl<<str;
Выводит только 5 символов, т.е. на 1 меньше, чем параметр в setw().
Это просто так реализовано? (думаю из-за '\0' в конце)
0
nmcf
6237 / 5549 / 2524
Регистрация: 14.04.2014
Сообщений: 23,331
20.10.2014, 11:55 #9
Разве setw() применим для ввода?
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
20.10.2014, 12:07 #10
Цитата Сообщение от nmcf Посмотреть сообщение
Разве setw() применим для ввода?
А почему бы нет? См. 27.7.4/7
C++
1
unspecified setw(int n);
Returns: An object of unspecified type such that if out is an instance of basic_ostream<charT,
traits> then the expression out << setw(n) behaves as if it called f(out, n), or if in is an object
of type basic_istream<charT, traits> then the expression in >> setw(n) behaves as if it called
f(in, n)
, where the function f is defined as:
C++
1
2
3
4
void f(ios_base& str, int n) {
// set width
str.width(n);
}
The expression out << setw(n) shall have type basic_ostream<charT, traits>& and value out.
The expression in >> setw(n) shall have type basic_istream<charT, traits>& and value in.
P.S. Вот надо отсюда и копать что там с eof происходит, имхо.
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
20.10.2014, 12:22 #11
Tulosba, всё же, eof устанавливается только при попытке чтения за пределы конца потока, то есть должна быть ошибка чтения. А вот как там действует setw на input stream -- это вопрос. Например, если Вы будете читать в char*, то поведение будет false.

На StackOverflow, по-моему, писали, что setw читает на один символ больше, ожидая нулевого символа завершения строки. Как-то так. Но я не могу быть уверен.
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
20.10.2014, 13:03 #12
Порылся немного в исходниках. Как я понял, прикол с eof возникает из-за различий в реализации цикла чтения из потока. В студии (VS2010) он такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (; 0 < _Size; --_Size, _Meta = _Istr.rdbuf()->snextc())
            if(_Traits::eq_int_type(_Traits::eof(), _Meta))
                {   // end of file, quit
                _State |= ios_base::eofbit;
                break;
                }
            else if (_Ctype_fac.is(_Ctype::space,
                _Traits::to_char_type(_Meta)))
                break;  // whitespace, quit
            else
                {   // add character to string
                _Str.append(1, _Traits::to_char_type(_Meta));
                _Changed = true;
                }
Т.е. проверка возврата snextc() на eof идет внутри цикла чтения (строки 2-4).
В gcc же имеем такой код (источник):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  while (__extracted < __n
              && !_Traits::eq_int_type(__c, __eof)
              && !__ct.is(__ctype_base::space,
                  _Traits::to_char_type(__c)))
         {
           if (__len == sizeof(__buf) / sizeof(_CharT))
             {
               __str.append(__buf, sizeof(__buf) / sizeof(_CharT));
               __len = 0;
             }
           __buf[__len++] = _Traits::to_char_type(__c);
           ++__extracted;
           __c = __in.rdbuf()->snextc();
         }
           __str.append(__buf, __len);
 
           if (_Traits::eq_int_type(__c, __eof))
         __err |= __ios_base::eofbit;
           __in.width(0);
         }
И теперь уже проверка на eof вынесена из цикла чтения (строки 17-18).
Поэтому как раз наблюдаем ситуацию: прочитали нормально n символов, но внутри считался ещё 1 дополнительно перед выходом из цикла. И после выхода как раз выставился eof (чего в варианте VS не происходит).

Стандарт же на этот счет говорит всего лишь следующее 21.4.8.9:
Inserters and extractors [string.io]
C++
1
2
3
4
template<class charT, class traits, class Allocator>
basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& is,
basic_string<charT,traits,Allocator>& str);
1 Effects: Behaves as a formatted input function (27.7.2.2.1). After constructing a sentry object, if the
sentry converts to true, calls str.erase() and then extracts characters from is and appends them to
str as if by calling str.append(1,c). If is.width() is greater than zero, the maximum number n
of characters appended is is.width(); otherwise n is str.max_size(). Characters are extracted and
appended until any of the following occurs:
— n characters are stored;
— end-of-file occurs on the input sequence;
— isspace(c,is.getloc()) is true for the next available input character c.
2 After the last character (if any) is extracted, is.width(0) is called and the sentry object k is destroyed.
3 If the function extracts no characters, it calls is.setstate(ios::failbit), which may throw ios_-base::failure (27.5.5.4).
4 Returns: is
Т.е. мы должны выйти из чтения по условию "n characters are stored;", после вызвать is.width(0) и уничтожить sentry объект. п.3 по идее сработать не должен. Т.о. имхо студия ведёт себя более правильно относительно Стандарта.
Но вот можно ли при этом утверждать что gcc не соответствует Стандарту, я не особо уверен.
1
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
20.10.2014, 13:15 #13
Цитата Сообщение от kravam Посмотреть сообщение
То есть если всё хорошо читается до конца-> поднимается флаг eofbit-> опускается флаг good. А он вроде как должен быть ПОДНЯТ, если всё хорошо считалось, он же всё-таки good!
Ты просто не понимаешь национальную логику авторов, а флаг good сбрасывается потому, что дальше читать без гоги уже нельзя.
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
20.10.2014, 13:51 #14
В gcc ещё, как оказалось, с символьным массивом будет поведение, отличное от std::string.
Т.е. такой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <sstream>
#include <iomanip>
 
using namespace std;
 
int main() {
    
    string str= "stroka";
    istringstream is (str);
    is >> setw(6);
    char arr[7];
    //is >> str;
    is >> arr;
    
    cout << "EOF is:" << boolalpha << is.eof() << endl;
    
    return 0;
}
http://ideone.com/DkxRV9
вернет eof() == true для std::string, но ==false для char[]. Хотя, казалось бы, поведение должно быть согласовано.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4371 / 2346 / 654
Регистрация: 18.10.2014
Сообщений: 3,996
20.10.2014, 18:08 #15
Цитата Сообщение от notemac Посмотреть сообщение
А если через строку, то
C++
1
2
3
4
5
char str = "stroka";
    istrstream is(str);
    is >> setw(6)>>str;
        ...
    cout<<endl<<str;
Выводит только 5 символов, т.е. на 1 меньше, чем параметр в setw().
Это просто так реализовано? (думаю из-за '\0' в конце)
Не совсем понимаю примера. У меня вышепроцитированным примером кода читается и выводится именно 6 символов, и в gcс, и в MSVC.

Если читать в массив 'char', то читаться действительно будет только 5 символов, т.е. на один меньше, чем указано в 'setw'. Но так и должно быть - стандарт это явно оговаривает. А если читать в 'std::string', то читаться будет 6 символов.

Добавлено через 2 минуты
Цитата Сообщение от Tulosba Посмотреть сообщение
вернет eof() == true для std::string, но ==false для char[]. Хотя, казалось бы, поведение должно быть согласовано.
Это как раз таки явно оговорено в стандарте. Для 'char []' читается 'n - 1' символ, а для 'string' - 'n' символов (где 'n' - величина, заданная в 'setw').
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
20.10.2014, 18:57 #16
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Для 'char []' читается 'n - 1' символ, а для 'string' - 'n' символов (где 'n' - величина, заданная в 'setw').
Ну тогда действительно поведение eof в gcc остается согласованным между char[] и std::string.
Но вот вопрос об установке самого значения eof пока не очень
0
20.10.2014, 18:57
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.10.2014, 18:57
Привет! Вот еще темы с решениями:

Нарисовать флаг России C++
#include &lt;graphics.h&gt; #include &lt;graph.h&gt; #include &lt;cstdlib&gt; #include...

Нарисовать флаг России
Нарисовать в консоли флаг России и Франции

Флаг компиляторов который -О
У компиляторов бывает флаг -О. Как правило после буквы идёт цифра, например...

Нарисовать флаг России
Помогите нарисовать флаг России в С++ через циклы


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru