So a quick Google search for fflush(stdin)
for clearing the input buffer reveals numerous websites warning against using it. And yet that's exactly how my CS professor taught the class to do it.
How bad is using fflush(stdin)
? Should I really abstain from using it, even though my professor is using it and it seems to work flawlessly?
Simple: this is undefined behavior, since
fflush
is meant to be called on an output stream. This is an excerpt from the C standard:So it's not a question of "how bad" this is.
fflush(stdin)
is plainly wrong, and you mustn't use it, ever.Quote from POSIX:
Note that terminal is not capable of seeking.
Converting comments into an answer — and extending them since the issue reappears periodically.
Standard C and POSIX leave
fflush(stdin)
as undefined behaviourThe POSIX, C and C++ standards for
fflush()
explicitly state that the behaviour is undefined, but none of them prevent a system from defining it.ISO/IEC 9899:2011 — the C11 Standard — says:
POSIX mostly defers to the C standard but it does mark this text as a C extension.
Note that terminals are not capable of seeking; neither are pipes or sockets.
Microsoft defines the behaviour of
fflush(stdin)
Microsoft and the Visual Studio runtime defines the define the behaviour of
fflush()
on an input stream.M.M notes:
This is why this answer version of my comment notes 'Microsoft and the Visual Studio runtime' — if you use a non-Microsoft C runtime library, the behaviour you see depends on that library.
Linux documentation and practice seem to contradict each other
Surprisingly, Linux nominally documents the behaviour of
fflush(stdin)
too, and even defines it the same way (miracle of miracles).I remain a bit puzzled and surprised at the Linux documentation saying that
fflush(stdin)
will work. Despite that suggestion, it most usually does not work on Linux. I just checked the documentation on Ubuntu 14.04 LTS; it says what is quoted above, but empirically, it does not work — at least when the input stream is a non-seekable device such as a terminal.demo-fflush.c
Example output
This output was obtained on both Ubuntu 14.04 LTS and Mac OS X 10.11.2. To my understanding, it contradicts what the Linux manual says. If the
fflush(stdin)
operation worked, I would have to type a new line of text to get information for the secondgetchar()
to read.Given what the POSIX standard says, maybe a better demonstration is needed, and the Linux documentation should be clarified.
demo-fflush2.c
Example output
Note that
/etc/passwd
is a seekable file. On Ubuntu, the first line looks like:On Mac OS X, the first 4 lines look like:
In other words, there is commentary at the top of the Mac OS X
/etc/passwd
file. The non-comment lines conform to the normal layout, so theroot
entry is:Ubuntu 14.04 LTS:
Mac OS X 10.11.2:
The Mac OS X behaviour ignores (or at least seems to ignore) the
fflush(stdin)
(thus not following POSIX on this issue). The Linux behaviour corresponds to the documented POSIX behaviour, but the POSIX specification is far more careful in what it says — it specifies a file capable of seeking, but terminals, of course, do not support seeking. It is also much less useful than the Microsoft specification.Summary
Microsoft documents the behaviour of
fflush(stdin)
. Apparently, it works as documented on the Windows platform, using the native Windows compiler and C runtime support libraries.Despite documentation to the contrary, it does not work on Linux when the standard input is a terminal, but it seems to follow the POSIX specification which is far more carefully worded. According to the C standard, the behaviour of
fflush(stdin)
is undefined. POSIX adds the qualifier 'unless the input file is seekable', which a terminal is not. The behaviour is not the same as Microsoft's.Consequently, portable code does not use
fflush(stdin)
. Code that is tied to Microsoft's platform may use it and it will work, but beware the portability issues.POSIX way to discard unread terminal input from a file descriptor
The POSIX standard way to discard unread information from a terminal file descriptor (as opposed to a file stream like
stdin
) is illustrated at How can I flush unread data from a tty input queue on a Unix system. However, that is operating below the standard I/O library level.According to the standard,
fflush
can only be used with output buffers, and obviouslystdin
isn't one. However, some compilers provide the use of fflush(stdin) as an extension. In that case you can use it, but it will affect portability, so you will no longer be able to use any standards-compliant compiler on earth and expect the same results.