Подскажите, пожалуйста.
Почему в FreeBSD функция fflush не чистит поток stdin. Если я к примеру ввожу букву вместо цифры при запросе функции scanf, то fflush не сбрасывает поток. Почему?
>Подскажите, пожалуйста.
>Почему в FreeBSD функция fflush не чистит поток stdin. Если я к
>примеру ввожу букву вместо цифры при запросе функции scanf, то fflush
>не сбрасывает поток. Почему?Вам же уже объясняли на nixp.ru, что согласно стандарту языка С fflush работает только на output потоках. Поведение на input НЕ ОПРЕДЕЛЕНО, что означает, что может случится ВСЕ что угодно начиная с ничего до core или атомного взрыва.
Удачи
--- sas
Доброго времени суток, sas!
Это курто!
Просто хотел узнать менение других умных людей, а на том форуме отвечаете только вы один. Ну, даладно ... В любом случае спасибо большое за ответ.
Интересно, а я этого не знал, хотя с давних пор общаюсь с С/С++. А как же всетаки очистить stdin, если fflush( stdin ) тут не работает (хотя под виндой я видел, и не раз, примеры обратного)
>Интересно, а я этого не знал, хотя с давних пор общаюсь с
>С/С++. А как же всетаки очистить stdin, если fflush( stdin )
>тут не работает (хотя под виндой я видел, и не раз,
>примеры обратного)Сходите на
http://www.nixp.ru/cgi-bin/forum/YaBB.pl?board=coding;action...Успехов
--- sas
Сходил. Да, круто вы там все разложили. Вот уж никогда не думал, что очистить поток ввода - это такая проблема. А виндовая функция fflush мне все же нравится. По моему, возможно сделать и так:void fflush_stdin( void )
{
while( не_конец_файла_стдин )
{
fgetc( stdin );
}
}
Я опробую этот код при первой же возможности, но хотелось бы
услышать ваше мнение
>Сходил. Да, круто вы там все разложили. Вот уж никогда не думал,
>что очистить поток ввода - это такая проблема. А виндовая функция
>fflush мне все же нравится. По моему, возможно сделать и так:
>
>
>void fflush_stdin( void )
>{
> while( не_конец_файла_стдин )
> {
> fgetc( stdin );
> }
>}
>Я опробую этот код при первой же возможности, но хотелось бы
>услышать ваше мнение
Этот цикл никогда не закончится (конечно если поток не перенаправлен в файл), т.к. в stdin нет EOF (End Of File)
>>Сходил. Да, круто вы там все разложили. Вот уж никогда не думал,
>>что очистить поток ввода - это такая проблема. А виндовая функция
>>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 termios2) "сырой" (noncanonical), когда например буферизация убрана, и данные передаются нам для обработки сразу (см termios).
Ответ
====
Исходя из вышеизложенного, на "ОБЫЧНОМ" терминале: Нет, такая очистка буфера работать не будет.Т.е. мы могли бы перейти в "сырой" режим (termios флаги и tcsetattr), но тогда нам самим бы пришлось разбирать ввод, т.е. делать кучу работы, которую для нас (scanf) уже кто-то сделал. И зачем?
Удачи
--- sas
Да, тот код действительно не работает. Однако я нашел более простое решение для ограниченного круга задач, связанного с получением ввода в текстовом меню. Допустим, что нам нужно чтобы работало меню такого типа:
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