Вопрос

Итак, быстрый поиск в Google fflush(stdin) Для очистки входного буфера раскрывает многочисленные веб -сайты, предупреждающие о его использовании. И все же именно так мой профессор CS научил класс, чтобы сделать это.

Как плохо использовать fflush(stdin)? Должен ли я действительно воздерживаться от его использования, хотя мой профессор использует его, и, кажется, работает безупречно?

Это было полезно?

Решение

Просто: это неопределенное поведение, поскольку fflush предназначено для вызова выходного потока. Это отрыв из стандарта C:

int fflush (file *ostream);

Ostream указывает на выходной поток или поток обновлений, в котором самая последняя операция не была вводой, функция FFLUSH вызывает любые неписаные данные для того, чтобы этот поток был доставлен в среду хоста, которая будет записана в файл; В противном случае поведение не определен.

Так что это не вопрос «как это плохо». fflush(stdin) является ясно неправильно, а вы не должен использовать его, никогда.

Другие советы

Преобразование комментариев в ответ - и расширение их с момента периодического появления вопроса.

Стандартный C и POSIX LEASE fflush(stdin) как неопределенное поведение

А Posix, C и C ++ Стандарты для fflush() Явно утверждает, что поведение не определено, но ни один из них не мешает системе определить ее.

ISO/IEC 9899: 2011 - Стандарт C11 - говорит:

§7.21.5.2 функция Fflush

¶2 Если stream указывает на выходной поток или поток обновлений, в котором самая последняя операция не была входом, fflush Функция приводит к доставке любых неписаных данных для этого потока в среду хоста, которые будут записаны в файл; В противном случае поведение не определен.

POSIX в основном выдерживает стандарт C, но он отмечает этот текст как расширение C.

CX] для открытого потока для чтения, если файл еще не находится в EOF, а файл способен искать, смещение файла базового описания открытого файла должно быть установлено в положение файла потока и любые символы отодвинулись на поток ungetc() или же ungetwc() которые впоследствии не были прочитаны из потока, должны быть отброшены (без дальнейшего изменения смещения файла).

Обратите внимание, что клеммы не способны искать; Ни трубы, ни розетки.

Microsoft определяет поведение fflush(stdin)

Microsoft и время выполнения Visual Studio определяет поведение fflush() На входном потоке.

Если поток открыт для ввода, fflush очищает содержимое буфера.

Мм заметки:

Cygwin является примером довольно распространенной платформы, на которой fflush(stdin) не очищает вход.

Вот почему этот ответ версию моего комментарий Примечания «Microsoft и визуальная среда выполнения студии»-если вы используете библиотеку выполнения не Microsoft C, то поведение, которое вы видите, зависит от этой библиотеки.

Документация и практика Linux, похоже, противоречат друг другу

Удивительно, Linux номинально документирует поведение fflush(stdin) тоже, и даже определяет его так же (чудо чудес).

Для входных потоков, fflush() Выбрасывает любые буферные данные, которые были извлечены из базового файла, но не использовались приложением.

Я остаюсь немного озадаченным и удивленным в документации Linux, говоря, что fflush(stdin) заработает. Несмотря на это предложение, это обычно не работает на Linux. Я только что проверил документацию на Ubuntu 14.04 LTS; В нем говорится, что цитируется выше, но эмпирически он не работает-по крайней мере, когда входной поток является невидимым устройством, таким как терминал.

demo-fflush.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c; enter some new data\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

Пример вывода

$ ./demo-fflush
Alliteration
Got A; enter some new data
Got l
$

Этот выход был получен как на Ubuntu 14.04 LTS, так и на Mac OS X 10.11.2. Насколько я понимаю, это противоречит тому, что говорит руководство Linux. Если fflush(stdin) Операция сработала, мне пришлось бы ввести новую линию текста, чтобы получить информацию для второго getchar() читать.

Учитывая то, что говорит стандарт POSIX, может быть, необходима лучшая демонстрация, и документация Linux должна быть прояснена.

demo-fflush2.c

#include <stdio.h>

int main(void)
{
    int c;
    if ((c = getchar()) != EOF)
    {
        printf("Got %c\n", c);
        ungetc('B', stdin);
        ungetc('Z', stdin);
        if ((c = getchar()) == EOF)
        {
            fprintf(stderr, "Huh?!\n");
            return 1;
        }
        printf("Got %c after ungetc()\n", c);
        fflush(stdin);
    }
    if ((c = getchar()) != EOF)
        printf("Got %c\n", c);

    return 0;
}

Пример вывода

Обратите внимание, что /etc/passwd это файл для поиска. На Ubuntu первая строка выглядит как:

root:x:0:0:root:/root:/bin/bash

На Mac OS X первые 4 строки выглядят как:

##
# User Database
# 
# Note that this file is consulted directly only when the system is running

Другими словами, есть комментарий в верхней части Mac OS X /etc/passwd файл. Линии без соревнования соответствуют нормальной макету, поэтому root Вход - это:

root:*:0:0:System Administrator:/var/root:/bin/sh

Ubuntu 14.04 LTS:

$ ./demo-fflush2 < /etc/passwd
Got r
Got Z after ungetc()
Got o
$ ./demo-fflush2
Allotrope
Got A
Got Z after ungetc()
Got B
$

Mac OS X 10.11.2:

$ ./demo-fflush2 < /etc/passwd
Got #
Got Z after ungetc()
Got B
$

Поведение Mac OS X игнорирует (или, по крайней мере, игнорирует) fflush(stdin) (Таким образом, не следуя POSIX по этому вопросу). Поведение Linux соответствует документированному поведению POSIX, но спецификация POSIX гораздо более осторожна в том, что он говорит - он определяет файл, способный искать, но терминалы, конечно, не поддерживают поиск. Это также гораздо менее полезно, чем спецификация Microsoft.

Резюме

Microsoft документирует поведение fflush(stdin). Анкет По -видимому, он работает так, как задокументировано на платформе Windows, используя нативные библиотеки компилятора Windows и поддержки выполнения C.

Несмотря на документацию наоборот, он не работает на Linux, когда стандартный ввод является терминалом, но, похоже, следует спецификации POSIX, которая гораздо более тщательно сформулирована. Согласно стандарту C, поведение fflush(stdin) не определен. POSIX добавляет квалификатор «если входной файл не является поиском», которого не является терминалом. Поведение не то же самое, что Microsoft.

Следовательно, портативный код не использует fflush(stdin). Анкет Код, привязанный к платформе Microsoft, может использовать его, и он будет работать, но остерегайтесь проблемы с портативностью.

POSIX способ отказаться

Стандартный способ сброса нечитанной информации из дескриптора файла терминала (в отличие от потока файла, подобного stdin) иллюстрируется в Как я могу снять непрочитанные данные из очереди ввода TTY в системе UNIX. Анкет Однако это работает ниже стандартного уровня библиотеки ввода/вывода.

Согласно стандарту, fflush можно использовать только с выходными буферами и, очевидно, stdin не один. Однако, немного Стандартные библиотеки C обеспечивают использование fflush(stdin) как расширение. В этом случае вы можете использовать его, но это повлияет на портативность, поэтому вы больше не сможете использовать какую-либо стандартную библиотеку C, соответствующую стандартам, на Земле и ожидать тех же результатов.

Цитата от Posix:

Для открытого потока для чтения, если файл еще не находится в EOF, а файл способен искать, смещение файла базового описания открытого файла должно быть установлено в положение файла потока, а любые символы наоткрыта обратно на поток ungetc () или ungetwc (), которые впоследствии не были прочитаны из потока, должны быть отменены (без дальнейшего изменения смещения файла).

Обратите внимание, что терминал не способен искать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top