быдлокодер
1722 / 909 / 106
Регистрация: 04.06.2008
Сообщений: 5,655
1

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

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

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

Это нонсенс, друзья.
Здесь прочтём, что флаг goodbit потока поднят, если опущены все флаги
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
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.10.2014, 21:28
Ответы с готовыми решениями:

Флаг failbit для перенаправления строкового потока; почему он всегда у меня поднят?
#include &lt;windows.h&gt; #include &lt;stdio.h&gt; #include &lt;sstream&gt; using namespace std; int main()...

Нарисовать на экране дисплея флаг РФ, Японский флаг
Нарисовать на экране дисплея флаг РФ, Японский флаг 300*200px Добавлено через 22 часа 20 минут ...

Получить флаг о готовности данных от дочернего потока
Доброго времени суток. Имеется следующая разработка: мини-прога, набор небольших утилит, основная...

Олимпийский флаг, почему не рисуется?
Нужно, чтобы выводился олимпийский флаг, а выводится пустая форма. Почему так? Код: unit...

15
7361 / 6284 / 2855
Регистрация: 14.04.2014
Сообщений: 27,223
19.10.2014, 21:34 2
Потому что читать больше нечего из потока.
0
быдлокодер
1722 / 909 / 106
Регистрация: 04.06.2008
Сообщений: 5,655
19.10.2014, 21:38  [ТС] 3
И поэтому я должен думать, что прочитано плохо или неправильно или вообще не прочитано?
0
7361 / 6284 / 2855
Регистрация: 14.04.2014
Сообщений: 27,223
19.10.2014, 21:43 4
Для этого есть отдельные три флага. good - это для того, чтобы начинать или не начинать новую операцию, а не для анализа старой.
1
Вездепух
Эксперт CЭксперт С++
10820 / 5841 / 1585
Регистрация: 18.10.2014
Сообщений: 14,496
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
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
20.10.2014, 10:43 6
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
то обнаружите, что никакого флага 'eof' при таком чтении не выставляется.
В gcc это не так:
http://coliru.stacked-crooked.... 2640cb899a
А вот в студии eof действительно не выставляется.
0
Вездепух
Эксперт CЭксперт С++
10820 / 5841 / 1585
Регистрация: 18.10.2014
Сообщений: 14,496
20.10.2014, 11:14 7
Это интересная деталь. Это, по-видимому, означает, что условие завершения чтения в gcc первым делом проверяет входной поток на пробельный символ и лишь потом проверяет ограничение на длину. Попытка проверки на пробельный символ (т.е. попытка чтения следующего символа) и выставляет eof.

Интересно, специфицирует ли стандарт языка порядок проверки условий завершения чтения.
0
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
7361 / 6284 / 2855
Регистрация: 14.04.2014
Сообщений: 27,223
20.10.2014, 11:55 9
Разве setw() применим для ввода?
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 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
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
20.10.2014, 12:22 11
Tulosba, всё же, eof устанавливается только при попытке чтения за пределы конца потока, то есть должна быть ошибка чтения. А вот как там действует setw на input stream -- это вопрос. Например, если Вы будете читать в char*, то поведение будет false.

На StackOverflow, по-моему, писали, что setw читает на один символ больше, ожидая нулевого символа завершения строки. Как-то так. Но я не могу быть уверен.
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 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
4203 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
20.10.2014, 13:15 13
Цитата Сообщение от kravam Посмотреть сообщение
То есть если всё хорошо читается до конца-> поднимается флаг eofbit-> опускается флаг good. А он вроде как должен быть ПОДНЯТ, если всё хорошо считалось, он же всё-таки good!
Ты просто не понимаешь национальную логику авторов, а флаг good сбрасывается потому, что дальше читать без гоги уже нельзя.
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 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
Вездепух
Эксперт CЭксперт С++
10820 / 5841 / 1585
Регистрация: 18.10.2014
Сообщений: 14,496
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
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.10.2014, 18:57
Помогаю со студенческими работами здесь

Сколькими способами можно сшить трехцветный флаг, если есть ткани 5 различных цветов?
Сколькими способами можно сшить трехцветный флаг, если есть ткани 5 различных цветов?

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

Задана 32-х битная переменная и набор 32-битных флагов. Если бит в заданной переменной равен единице то считать,что соответствующий флаг установлен...
Задана 32-х битная переменная и набор 32-битных флагов. Если бит в заданной переменной равен...

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


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru