5

I know this is gonna be quite a stupid question, but after reading so many document about the whole "buffer" system, I can't understand why would people flush a stream but not a buffer.

I have seen people write thing like this:

FILE* file=fopen("mytext.txt","wr");
char buffer[10]="";
setbuf(file,buffer);

//do some stuff....

fflush(file);
....
fclose(file);

So I wonder, since we actually store things in the buffer, why do we flush the stream it is associated to rather than flush the buffer directly, which actually store something and should be flushed.( well, some people tell me that if things go like what I said it will just be the same thing so bother myself......)

For example, we can't write things likefflush(buffer).Why?

walkerlala
  • 1,599
  • 1
  • 19
  • 32

3 Answers3

6

Flushing copies data from the stream's internal buffer to the underlying file.

So the flushing function needs to know the source and the destination to copy.

This depends on I/O implementation, for C++ <iostream> see Jerry Coffin's answer - the buffers in <iostream> are more smart.

With C-style <cstdio>, if you want to flush with just one argument, either FILE* or the char array needs to know about the file it should copy to.

Your buffer is a dumb array, it just stores data for reading/writing. Since there are no additional info there, the function that gets a pointer to the buffer can't know the destination where to write it - so the imaginary fflush call would look like fflush(buffer, file); which doesn't get you anywhere. On the other hand, the FILE* stores the pointer to your buffer (you set the pointer with the setbuf(file,buffer) function call).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
milleniumbug
  • 15,379
  • 3
  • 47
  • 71
  • Actually, milleniumbug is right. The question was asking about stdio.h functions, not C++ streams, contrary to what was implied by the title of the question. The code example makes clear that the buffer is just a char * pointer, and the question refers to setbuf and fflush functions. This pointer does indeed have no knowledge of the file. – David Roundy May 30 '15 at 00:02
  • @JerryCoffin Reworded the answer a bit (it was too sloppy with the words "stream", "buffer" and "file"). – milleniumbug May 30 '15 at 00:05
  • @DavidRoundy: Ah, good point. I paid too much attention to the tag, and not enough to the example code. – Jerry Coffin May 30 '15 at 02:12
2

The following deals only with iostreams and their buffer objects. For information about the buffers related to C-style I/O, please see @milleniumbug's answer.

Mostly because you (at least normally) want the stream's badbit set if attempting to flush the underlying buffer fails.

There's also a slightly complex little dance that streams use when interacting with the underlying stream, where the stream creates a sentry object, then carries out an action, then the sentry object is destroyed. The sentry is intended to make prefix and suffix operations exception safe.

So the overall sequence is something like this:

create sentry
if that succeeds (sentry converts to true) call rdbuf()->pubsync()
    if that fails (returns -1) setstate(badbit);

A stream buffer (e.g., a basic_filebuf) is directly attached to the underlying file system object--in fact, all the interaction between the iostream object and the underlying file object is done via the file buffer. As shown above, when the stream object does need to flush the buffer, all it needs to do it tell the buffer to flush itself by calling the buffer's pubsync() member function.

[For reference: [ostream.unformatted]/7:

basic_ostream& flush();

Effects: Behaves as an unformatted output function (as described in 27.7.3.6.1, paragraph 1). If rdbuf() is not a null pointer, constructs a sentry object. If this object returns true when converted to a value of type bool the function calls rdbuf()->pubsync(). If that function returns -1 calls setstate(badbit) (which may throw ios_base::failure (27.5.5.4)). Otherwise, if the sentry object returns false, does nothing.

Returns: *this.

...and [ofstream.cons]/2:

explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);

Effects: Constructs an object of class basic_ofstream, initializing the base class with basic_ostream(&sb) and initializing sb with basic_filebuf()) (27.7.3.2, 27.9.1.2), then calls rdbuf()->open(s, mode|ios_base::out). If that function returns a null pointer, calls setstate(failbit).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

I can't understand why would people flush a stream but not a buffer.

Because a buffer has no knowledge of where it should be flushed to. A stream does.

FILE* file=fopen("mytext.txt","wr");
setbuf(file,buffer);

By default, a FILE structure contains a pointer to its own internal buffer. setbuf() replaces that buffer with one that the caller provides. But either way, fwrite(), fput...() and other similar functions write data into the stream's current buffer, and fflush() flushes the content of that buffer to the underlying file.

BTW, setbuf() requires the caller-provided buffer to be at least BUFSIZ in size:

char buffer[BUFSIZ]="";

So I wonder, since we actually store things in the buffer, why do we flush the stream it is associated to rather than flush the buffer directly, which actually store something and should be flushed.

Because the buffer is just data storage. It does not know anything about how the data is being used. The stream knows what its buffer is being used for (cache written data), and where it needs to be flushed to (the associated file). So you have to flush the stream so it can utilize that information.

For example, we can't write things like fflush(buffer). Why?

And where would you expect the buffer to flush its content to? It has no such information.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770