fflush (stdin) не работает, скомпилировано с помощью gcc в cygwin, но скомпилировано с помощью Visual Studio 2010

Я (пере) изучаю программирование и начал с C. Моя IDE (если можно так сказать) - cygwin (32Bit) и Visual-Studio 2010 на Windows7. Я всегда компилирую код, который пишу, с помощью gcc (cygwin), а также с помощью компилятора VS2010. Думаю, я так делаю, потому что считаю, что это хороший способ обучения. Во всяком случае, я только что узнал о fflush (stdin), т.е. очистке буфера stdin. Кажется, хорошая функциональность, потому что иначе использование scanf кажется проблемой. Поэтому я написал приведенный ниже код на основе примера из моего учебника. Он компилируется как с gcc в cygwin, так и с VS2010. Когда я запускаю скомпилированную программу VS, она работает нормально (см. Ниже), когда я запускаю скомпилированную программу gcc в cygwin, fflush (stdin) не сбрасывает буфер stdin (см. Ниже). Я читал несколько тем о том, что fflush (stdin) в некоторых случаях имеет неопределенное поведение. Что бы это ни значило, я взял это из учебника программирования C для Linux. Если fflush (stdin) не является допустимым средством избавления от содержимого в буфере stdin, какой еще стандартный метод существует?

Большое спасибо за любые ответы!

== Программа запускается под Windows:

enter a long integer and a double
23.00 78.99
lint = 23
dt = 0.00

enter a five digits input
78493
u entered 78 and 493

== Программа запускается в Cygwin:

enter a long integer and a double
23.00 78.99
lint = 23
dt = 0.00

enter a five digits input
u entered 78 and 2665720

== КОД ====

long lint;
double dt;
int fp, sp;
char fn[50], ln[50];

/* using the l modifier to enter long integers and doubles */
puts ("enter a long integer and a double");
scanf("%ld %lf", &lint, &dt);

printf("lint = %d\ndt = %.2f\n", lint, dt);

fflush(stdin); /*DOES NOT WORK UNDER CYGWIN!?*/

/* use field width to split input */

puts("\nenter a five digits input");
scanf("%2d %3d", &fp, &sp);

printf("u entered %d and %d\n", fp, sp);

person user3010324    schedule 19.11.2013    source источник


Ответы (4)


C11 в 7.21.5.2.2 говорит (выделено мной):

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

Это означает, что вы не должны вызывать fflush во входном потоке (если вы не пишете код для очень конкретной операционной системы и библиотеки, в которой определено поведение)

На то есть веская причина! Обычно вы думаете, что fflush(stdin) сбрасывает строку, которую вы только что ввели, верно? Что ж, это еще не все. Представьте, что вы запускаете свою программу так:

$ ./program < input_file

В этом случае теоретически весь файл уже находится в буфере stdin. Следовательно, очистка этого буфера равносильна завершению ввода, что является довольно бесполезной операцией. По этим причинам fflush не может иметь очень разумное поведение во входных потоках, и поэтому для них оно не определено.


Если вы хотите игнорировать текущую строку, есть способы сделать это лучше. Вот один из примеров:

void flush_line(FILE *fin)
{
    int c;
    do
    {
        c = fgetc(fin);
    } while (c != '\n' && c != EOF);
}

Это считывает вводимый символ за символом и останавливается до тех пор, пока не произойдет конец файла, ошибка чтения или конец строки.

person Shahbaz    schedule 19.11.2013

В стандарте fflush () не определен для входных потоков. В документации Microsoft это явно определено .

В результате, хотя вы можете использовать его с библиотекой Microsoft C с четко определенным поведением, такое поведение не переносимо.

Если вы хотите использовать GCC и выполнить эту работу, вы можете использовать MinGW / GCC, поскольку он использует среду выполнения Microsoft C, а не glibc.

person Clifford    schedule 19.11.2013
comment
+1 спасибо, что работает. Почему fflush (stdin) работает, а flushall () не работает? pastebin.com/raw.php?i=ipcfQfRD - person barlop; 13.07.2015
comment
@barlop: Мне пришлось перейти по вашей ссылке, чтобы обнаружить, что под неработающим вы подразумеваете отсутствие ссылки. В контексте этого вопроса было разумным предположением, что вы имели в виду, что это не очищает входные буферы. Возможно, вам стоит задать отдельный вопрос? Однако в библиотеке MS flushall() устарел в пользу _ 2_. - person Clifford; 13.07.2015
comment
@barlop: Хорошо; однако задайте вопрос в следующий раз - это не цель комментариев к SO. Размещая вопрос, вы получите более широкую аудиторию и более быстрый ответ, а также добавите ресурс, который будет полезен для всех. Вам повезло, что через два года после публикации ответа на этот вопрос я даже прочитал ваш комментарий. - person Clifford; 13.07.2015

Не следует сбрасывать поток ввода. Различия, которые вы наблюдаете, связаны с тем, что поведение этих операций не определено.

person Paul92    schedule 19.11.2013
comment
Ссылка, которую вы предоставили, и связанные ссылки содержат несколько хороших советов, но в то же время кажется, что они написаны кем-то, не имеющим ни малейшего представления о C. Некоторые из утверждений в лучшем случае просто неверны или неточны. . Будь осторожен. - person Shahbaz; 20.11.2013

Насколько я понимаю, вы пишете эту программу для Linux и, хотите верьте, хотите нет, fflush(stdin) работает только под Windows. (По крайней мере, это то, что я получил из моей книги C под названием C для чайников). Альтернативой fflush(stdin) в Linux является fpurge(stdin). Попробуйте и посмотрите, сработает ли он для вас.

person naynay    schedule 25.06.2017