URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 3180
[ Назад ]

Исходное сообщение
"scanf & fflush"

Отправлено Fatal , 17-Июл-04 00:59 
Подскажите, пожалуйста.
Почему в FreeBSD функция fflush не чистит поток stdin. Если я к примеру ввожу букву вместо цифры при запросе функции scanf, то fflush не сбрасывает поток. Почему?

Содержание

Сообщения в этом обсуждении
"scanf & fflush"
Отправлено sas , 17-Июл-04 06:13 
>Подскажите, пожалуйста.
>Почему в FreeBSD функция fflush не чистит поток stdin. Если я к
>примеру ввожу букву вместо цифры при запросе функции scanf, то fflush
>не сбрасывает поток. Почему?

Вам же уже объясняли на nixp.ru, что согласно стандарту языка С fflush работает только на  output  потоках. Поведение на input НЕ ОПРЕДЕЛЕНО, что означает, что может случится ВСЕ что угодно начиная с ничего до core или атомного взрыва.

Удачи
--- sas


"scanf & fflush"
Отправлено Fatal , 17-Июл-04 09:55 
Доброго времени суток, sas!
Это курто!
Просто хотел узнать менение других умных людей, а на том форуме отвечаете только вы один. Ну, даладно ... В любом случае спасибо большое за ответ.

"scanf & fflush"
Отправлено dimus , 20-Июл-04 08:31 
Интересно, а я этого не знал, хотя с давних пор общаюсь с С/С++. А как же всетаки очистить stdin, если fflush( stdin ) тут не работает (хотя под виндой я видел, и не раз, примеры обратного)

"scanf & fflush"
Отправлено sas , 20-Июл-04 08:38 
>Интересно, а я этого не знал, хотя с давних пор общаюсь с
>С/С++. А как же всетаки очистить stdin, если fflush( stdin )
>тут не работает (хотя под виндой я видел, и не раз,
>примеры обратного)

Сходите на
http://www.nixp.ru/cgi-bin/forum/YaBB.pl?board=coding;action...

Успехов
--- sas


"scanf & fflush"
Отправлено dimus , 23-Июл-04 14:10 
Сходил. Да, круто вы там все разложили. Вот уж никогда не думал, что очистить поток ввода - это такая проблема. А виндовая функция fflush мне все же нравится. По моему, возможно сделать и так:

void fflush_stdin( void )
{
  while( не_конец_файла_стдин )
  {
    fgetc( stdin );
  }
}
Я опробую этот код при первой же возможности, но хотелось бы
услышать ваше мнение


"scanf & fflush"
Отправлено Fatal , 23-Июл-04 20:10 
>Сходил. Да, круто вы там все разложили. Вот уж никогда не думал,
>что очистить поток ввода - это такая проблема. А виндовая функция
>fflush мне все же нравится. По моему, возможно сделать и так:
>
>
>void fflush_stdin( void )
>{
>  while( не_конец_файла_стдин )
>  {
>    fgetc( stdin );
>  }
>}
>Я опробую этот код при первой же возможности, но хотелось бы
>услышать ваше мнение


Этот цикл никогда не закончится (конечно если поток не перенаправлен в файл), т.к. в stdin нет EOF (End Of File)


"scanf & fflush"
Отправлено sas , 24-Июл-04 15:33 
>>Сходил. Да, круто вы там все разложили. Вот уж никогда не думал,
>>что очистить поток ввода - это такая проблема. А виндовая функция
>>fflush мне все же нравится. По моему, возможно сделать и так:
>>
>>
>>void fflush_stdin( void )
>>{
>>  while( не_конец_файла_стдин )
>>  {
>>    fgetc( stdin );
>>  }
>>}
>>Я опробую этот код при первой же возможности, но хотелось бы
>>услышать ваше мнение
>
>
>Этот цикл никогда не закончится (конечно если поток не перенаправлен в файл),
>т.к. в stdin нет EOF (End Of File)

Теория
=====
Мы должны различать 2 типа настройки терминалов:
1) "обычный", или буферизированный (canonical), когда данные передаются в пользовательскую программу в следующих случаях:
   а) В буфере появилось: новая строка (NL), EOF или конец строки (EOL). Кстати EOF в DOS - это Ctrl+Z, а в Unix - Ctrl+D (ВАЖНО что бы они были первыми в строке). Если EOF произошел и мы еще собираемся использванть stdin, то надо вызвать clearerr
   б) Буфер заполнился полностью и у нас нет больше места, а NL/EOF/EOL все нет. В этом случае поведение системы зависит от termio c_iflag. Подробнее смотри в man termios

2) "сырой" (noncanonical), когда например буферизация убрана, и данные передаются нам для обработки сразу (см  termios).

Ответ
====
Исходя из вышеизложенного, на "ОБЫЧНОМ" терминале: Нет, такая очистка буфера работать не будет.

Т.е. мы могли бы перейти в "сырой" режим (termios флаги и tcsetattr), но тогда нам самим бы пришлось разбирать ввод, т.е. делать кучу работы, которую для нас (scanf) уже кто-то сделал. И зачем?

Удачи
--- sas



"scanf & fflush"
Отправлено dimus , 28-Июл-04 08:41 
Да, тот код действительно не работает. Однако я нашел более простое решение для ограниченного круга задач, связанного с получением ввода в текстовом меню. Допустим, что нам нужно чтобы работало меню такого типа:
1 - сделай то-то
2 - сделай что-то другое
h - поприветствуй всех собравшихся
0 - выйти
Тогда в цикле while можно использовать такую функцию:

int get_menu_char( FILE* fp )
{
   int result;
   // Получим то, что нам нужно
   result = fgetc( fp );
   // Проверим на конец файла из параноидальных соображений
   // Проглотим весь мусор
   while( !feof(fp) && ( fgetc(fp) !='\n') );
   return result;
}

Не знаю, может еще добавить туда сброс флага конца файла - я еще не решил, надо ли это. Но тестовая програмка работала прекрасно. Насчет scanf: я не использую функции, которые не контролируют объем ввода, т.к. это прямой путь к дырявой программе. Может быть я несправедлив к scanf, однако:
char msg[MAX_MSG];
scanf("%s", msg);
Это находка для любителей атак переполнением буфера. Я предпочитаю fgets.

Кстати, а где можно найти ТОЛКОВУЮ информацию по переключению терминала в другие режимы. Все, что я читал по этому вопросу было очень невнятно, а вещь ведь интересная и нужная.

С уважением, dimus