Difference between int fpurge() and int fflush() in C - c

Can anyone please explain me about difference between fpurge(FILE *stream) and fflush(FILE *stream) in C?
Both fflush() and fpurge() will discard any unwritten or unread data in the buffer.
Please explain me the exact difference between these two and also their pros and cons.

"... both fflush and fpurge will discard any unwritten or unread data in the buffer..." : No.
fflush:
The function fflush forces a write of all buffered data for the given output or update stream via the stream's underlying write function. The open status of the stream is unaffected.
If the stream argument is NULL, fflush flushes all open output streams.
fpurge:
The function fpurge erases any input or output buffered in the given stream. For output streams this discards any unwritten output. For input streams this discards any input read from the underlying object but not yet obtained via getc. This includes any text pushed back via ungetc. (P.S.: there also exists __fpurge, which does the same, but without returning any value).
Besides the obvious effect on buffered data, one use where you would notice the difference is with input streams. You can fpurge one such stream (although it is usually a mistake, possibly conceptual). Depending on the environment, you might not fflush an input stream (its behaviour might be undefined, see man page). In addition to the above remarked differences: 1) the cases where they lead to errors are different, and 2) fflush can work on all output streams with a single statement, as said (this might be very useful).
As for pros and cons, I would not really quote any... they simply work different (mostly), so you should know when to use each.
In addition to the functional difference (what you were asking), there is a portability difference: fflush is a standard function, while fpurge is not (and __fpurge is not either).
Here you have the respective man pages (fflush, fpurge).

To start with, both the functions clear the buffers (type of operable buffers are discussed below), the major difference is what happens with the data present in the buffer.
For fflush(), the data is forced to be written to disk.
For fpurge(), data is discarded.
That being said, fflush() is a standard C function, mentioned in the C11, chapter §7.21.5.2.
Whereas, fpurge() is a non-portable and non-standard function. From the man page
These functions are nonstandard and not portable. The function
fpurge() was introduced in 4.4BSD and is not available under Linux.
The function __fpurge() was introduced in Solaris, and is present in
glibc 2.1.95 and later.
That said, the major usage-side difference is,
Calling fflush() with input stream is undefined behavior.
If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is
undefined.
Calling fpurge() with input stream is defined.
For input streams
this discards any input read from the underlying object but not yet
obtained via getc(3); this includes any text pushed back via
ungetc(3).
Still, try to stick to fflush().

Related

why an input function cannot follow an output function without an intervening call to fflush?

I'm new to C and I was reading a textbook which says that:
Standard I/O streams are full duplex in the sense that programs can perform input and output on the same stream. However, there are poorly documented restrictions on streams
Restriction 1: Input functions following output functions. An input function
cannot follow an output function without an intervening call to fflush, fseek, fsetpos, or rewind
Restriction 2: Output functions following input functions. An output function
cannot follow an input function without an intervening call to fseek,
fsetpos, or rewind, unless the input function encounters an end-of-file.
I'm confused, below is my questions:
Q1-My understanding about the stream buffer is, each stream has two buffers, a read buffer and a write buffer, and is my understanding correct?
Q2-why we have to resposition the current file position or flush the output buffer when input functions following output functions or vice versa?
the stream buffer is, each stream has two buffers, a read buffer and a write buffer, ...
Maybe. 2 or 1 buffers are not required, yet buffering is performance practical.
why we have to....
That is what is needed to meet the specification. Specs were written to provide implementers some latitude - but not too much.
With tight specs, come limited implementation possibilities (no so efficient code).

Why can't an output be followed by an input and vice versa?

From APUE
When a file is opened for reading and writing (the plus sign
in the type), two restrictions apply.
• Output cannot be directly followed by input without an
intervening fflush, fseek, fsetpos, or rewind.
• Input cannot be directly followed by output without an
intervening fseek, fsetpos, or rewind, or an input operation that
encounters an end of file.
Why "fseek, fsetpos, or rewind" in both cases?
Why "an input operation that encounters an end of file" in the second case?
Thanks.
A similar question for Linux API is Can `read()` be directly followed by `write()` and `write()` by `read()`?
When working with a FILE stream, there is a single internal buffer used when either reading from or writing to the file.
When switching between reading and writing, that buffer must be cleared before switching modes, otherwise data loss could potentially occur. Each of the operations mentioned above perform the required flushing of the buffer.
the C standard doesn't say file positioning functions internally flush output to device or clear input cache.
The Standard indeed hasn't mentioned about the detail of somewhat internal buffering mechanism, because it varies from OS to OS; that is, implementation dependent. Thus, the standard is not responsible for defining it.
I was wondering why the file positioning functions (if not fflush) should be called between output and input?
Since the behaviour is implementation dependent, for some OS (e.g. Ubuntu), interestingly, there is no need for us to call fflush(),fseek() explicitly, while others(e.g. macOS) strictly needs.
For the sake of a concrete description, I've run some tests on two OS:
macOS Big Sur (Darwin Kernel Version 20.6.0)
Ubuntu 14 (GNU/Linux 4.4.0-142-generic)
Taking an example of "replace the 5th character in the file", and assume that the file content is
1234_6789
and the program is as followes:
show_file_content();
getc(fp);
getc(fp);
getc(fp);
getc(fp);
/* this line is indispensable for macos, but NOT for ubuntu */
fseek(fp,0,SEEK_CUR);
putc('5', fp);
printf("->");
show_file_content();
the above program's output is (no matter running on macOS or Ubuntu):
1234_6789->123456789
But, if we comment the line of fseek, things are different; the outputs are...
macOS:
1234_6789->1234_67895
Ubuntu:
1234_6789->123456789
You can try this test on other different OSes. The comparison between two different Unix-based OSes suffices to understand the APUE's statement.

Skip in standard input/output stream [duplicate]

We know that call to functions like fprintf or fwrite will not write data to the disk immediately, instead, the data will be buffered until a threshold is reached. My question is, if I call the fseek function, will these buffered data writen to disk before seeking to the new position? Or the data is still in the buffer, and is writen to the new position?
cheng
I'm not aware if the buffer is guaranteed to be flushed, it may not if you seek to a position close enough. However there is no way that the buffered data will be written to the new position. The buffering is just an optimization, and as such it has to be transparent.
Yes; fseek() ensures that the file will look like it should according to the fwrite() operations you've performed.
The C standard, ISO/IEC 9899:1999 §7.19.9.2 fseek(), says:
The fseek function sets the file position indicator for the stream pointed to by stream.
If a read or write error occurs, the error indicator for the stream is set and fseek fails.
I don't believe that it's specified that the data must be flushed on a fseek but when the data is actually written to disk it must be written at that position that the stream was at when the write function was called. Even if the data is still buffered, that buffer can't be written to a different part of the file when it is flushed even if there has been a subsequent seek.
It seems that your real concern is whether previously-written (but not yet flushed) data would end up in the wrong place in the file if you do an fseek.
No, that won't happen. It'll behave as you'd expect.
I have vague memories of a requirement that you call fflush before
fseek, but I don't have my copy of the C standard available to verify.
(If you don't it would be undefined behavior or implementation defined,
or something like that.) The common Unix standard specifies that:
If the most recent operation, other than ftell(), on a given stream is
fflush(), the file offset in the underlying open file description
shall be adjusted to reflect the location specified by fseek().
[...]
If the stream is writable and buffered data had not been written to
the underlying file, fseek() shall cause the unwritten data to be
written to the file and shall mark the st_ctime and st_mtime fields of
the file for update.
This is marked as an extention to the ISO C standard, however, so you can't count on it except on Unix platforms (or other platforms which make similar guarantees).

Why no other operations on file can be performed before setvbuf?

The documentation for glibc setvbuf (http://man7.org/linux/man-pages/man3/setvbuf.3p.html) states:
The setvbuf() function may be used after the stream pointed to by
stream is associated with an open file but before any other operation
(other than an unsuccessful call to setvbuf()) is performed on the
stream.
What is the point of having this restriction? (but before any other operation...)
Why it it not possible to first write to the file and then call setvbuf() for example?
I suspect that this restriction was taken literally from Unix OS. Referring to Rationale for ANSI C:
4.9.5.6 The setvbuf function
setvbuf has been adopted from UNIX System V, both to control the
nature of stream buffering and to specify the size of I/O buffers.
A particular implementation may provide useful mechanics for UB in form of non-portable extension. It is easier for output streams, which may be just flushed, but it gets less trivial for input streams.
Without crystal ball, I guess that it is easier to reopen the file and set the buffer, rather that think of every edge case involved in rebuffering.

Is this the proper way to flush the C input stream?

Well I been doing a lot of searching on google and on here about how to flush the input stream properly. All I hear is mixed arguments about how fflush() is undefined for the input stream, and some say just do it that way, and others just say don't do it, I haven't had much luck on finding a clear efficient/proper way of doing so, that the majority of people agree on.. I am quite new at programming so I don't know all the syntax/tricks of the language yet, so my question which way is the most efficient/proper solution to clearing the C input stream??
Use the getchar() twice before I try to receive more input?
Just use the fflush() function on the input? or
This is how I thought I should do it.
void clearInputBuf(void);
void clearInputBuf(void)
{
int garbageCollector;
while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF)
{}
}
So, whenever I need to read a new scanf(), or use getchar() to pause the program I just call the clearInputBuf.. So what would be the best way out of the three solutions or is there a even better option?
All I hear is mixed arguments about how fflush() is undefined for the input stream
That's correct. Don't use fflush() to flush an input stream.
(A) will work for simple cases where you leave single character in the input stream (such as scanf() leaving a newline).
(B) Don't use. It's defined on some platforms. But don't rely on what standard calls undefined behaviour.
(C) Clearly the best out of the 3 options as it can "flush" any number of characters in the input stream.
But if you read lines (such as using fgets()), you'll probably have much less need to clear input streams.
It depends on what you think of as "flushing an input stream".
For output streams, the flush operation makes sure that all data that were written to the stream but were being kept buffered in memory have been flushed to the underlying filesystem file. That's a very well defined operation.
For input streams, there is no well defined operation of what flushing the stream should do. I would say that it does not make any sense.
Some implementations of the C standard library redefine the meaning of "flush" for input streams to mean "clear the rest of the current line which has not been read yet". But that's entirely arbitrary, and other implementations choose to do nothing instead.
As of C11 this disparity has been corrected, and the standard now explicitly states that the fflush() function does not work with input streams, precisely because it makes no sense, and we do not want each runtime library vendor to go implementing it in whatever way they feel like.
So, please by all means do go ahead and implement your clearInputBuf() function the way you did, but do not think of it as "flushing the input stream". There is no such thing.
It turns out to be platform dependent.
The fflush() cannot have an input stream as a parameter because according to the c standard, IT'S UNDEFINED BEHAVIOR since the behavior is not defined anywhere.
On Windows, there is a defined behavior for fflush() and it does what you need it to do.
On Linux, there is fpurge(3) which does what you want it to do too.
The best way is to simply read all characters in a loop until
A newline character is found.
EOF is returned from getchar().
like your clearInputBuf() function.
Note that flushing an output stream means writing all unwritten data to the stream, the data that is still in a buffer waiting to be flushed. But reading all the unread bytes from a stream, does not have the same meaning.
That's why it doesn't make sense to fflush() an input stream. On the other hand fpurge() is designed specifically for this, and it's name is a better choice because you want to clear the input stream and start fresh. The problem is, it's not a standard function.
Reading fpurge(3) should clarify why fflush(stdin) is undefined behavior, and why an implementation like the one on Windows doesn't make sense because it makes fflush() behave differently with different inputs. That's like making c compliant with PHP.
The problem is more subtile than it looks:
On systems with elaborate terminal devices, such as unix and OS/X, input from the terminal is buffered at 2 separate levels: the system terminal uses a buffer to handle line editing, from just correcting input with backspace to full line editing with cursor and control keys. This is called cooked mode. A full line of input is buffered in the system until the enter key is typed or the end-of-file key combination is entered.
The FILE functions perform their own buffering, which is line buffered by default for streams associated with a terminal. The buffer size in set to BUFSIZ by default and bytes are requested from the system when the buffered contents have been consumed. For most requests, a full line will be read from the system into the stream buffer, but in some cases such as when the buffer is full, only part of the line will have been read from the system when scanf() returns. This is why discarding the contents of the stream buffer might not always suffice.
Flushing the input buffer may mean different things:
discarding extra input, including the newline character, that have been entered by the user in response to input requests such as getchar(), fgets() or scanf(). The need for flushing this input is especially obvious in the case of scanf() because most format lines will not cause the newline to be consumed.
discarding any pending input and waiting for the user to hit a key.
You can implement a fluch function portably for the first case:
int flush_stream(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
return c;
}
And this is exactly what your clearInputBuf() function does for stdin.
For the second case, there is no portable solution, and system specific methods are non trivial.

Resources