Stream buffers are used by streams for actual transport of characters to or from an external i/o device; they hold an internal buffer where these characters are buffered. The streams are responsible for parsing the input and formatting the output.
When we do: std::cout << std::setw(15) << number ; the stream formats the number in a field of width 15, and forwards the formatted characters to its associated stream buffer. The stream buffer may hold these in its internal buffer.
When we do: std::cout << std::flush ; the stream instructs the stream buffer to immediately send out the unwritten characters in its internal buffer to the external output device.
Yeah, by default, each std::iostream has a "built-in" buffer.
This means when writing data into the stream, the data is not written straight into the destination file, but is sent to the buffer first. Only when the buffer is full, or when the buffer is explicitly flushed, or when the stream is closed, then the buffer is actually written (flushed) into the file. Similarly, when reading data from a stream, then a full "block" of data is read from the file into the buffer, even if you only read a single byte. Subsequent reads are then served from the buffer, until the buffer becomes empty - then the next "block" is loaded.
Now, when a stream is connected to a TTY (e.g. terminal), then the buffering is usually disabled automatically by the runtime environment! And, since the std::cout, std::cerr and std::cin normally are connected to a TTY (e.g. terminal), those will usually be un-buffered. The reasoning is that we generally want output to the terminal to appear right away and not be "delayed" until a stream "flush" happens. Also, reading or writing data in a "block-wise" fashion is good for regular files, but probably has no advantage for terminals...
(You will notice this, when your stdout happens to be connected to a pipe rather than a terminal. In that situation, the stream buffering is not disabled by default, since in that case the stdout is not connected to a TTY, so the data written to std::cout will not arrive at the pipe until an explicit "flush" is performed!)
Now, when a stream is connected to a TTY (e.g. terminal), then the buffering is usually disabled automatically by the runtime environment! And, since the std::cout, std::cerr and std::cin normally are connected to a TTY (e.g. terminal), those will usually be un-buffered. The reasoning is that we generally want output to the terminal to appear right away and not be "delayed" until a stream "flush" happens. Also, reading or writing data in a "block-wise" fashion is good for regular files, but probably has no advantage for terminals...
I don't think this is true.
If I output something with std::cout without flushing (e.g. by using std::flush or std::endl) and without a newline character and without using std::cin or std::cerr, then I don't see anything right away (unless I output a lot so that the buffer gets full).
Typically, std::cout and std::wcout are line-buffered (writing a newline triggers a flush) by default. std::cerr and std::wcerr are not buffered; every output operation triggers a flush. std::clog and std::wclog are fully buffered (they never automatically flushed).
I would say, technically, none of C++ I/O streams use buffering by default (when sync_with_stdio is on) - not std::cerr, not std::cout,
They both immediately transmit every single byte written to the corresponding C I/O stream (stderr, stdout).
*those* streams are what's fully/line-/non-buffered, depending on how the program was invoked and whether any other APIs were called
(buit I suppose in "just started learning" phase, the distinction between C++ layer's buffer and C layer's buffer is not that important.. except to understand the mechanics of, e.g, this line from above:
std::ios::sync_with_stdio(false); // essentially disables automatic flushing at the end of lines
this enabled buffering in the C++ layer, and C++ buffers don't have special treatment for \n)
If I output something with std::cout without flushing (e.g. by using std::flush or std::endl) and without a newline character and without using std::cin or std::cerr, then I don't see anything right away (unless I output a lot so that the buffer gets full).
It is true ;-)
std::cout and friends do not buffer (or they flush implicitly), when they are connected to a TTY.
#include <cstdio>
int main()
{
do
{
constint c = fgetc(stdin);
if (c == EOF)
{
break;
}
fputc(c, stdout);
fflush(stdout); /* just to be sure that there is *no* buffering in test.exe */
}
while (true);
}
If we run program.exe directly in the terminal, so that it's stdout is connected directly to the terminal (TTY), then there is no buffering at all! Or, for the very least, there is an implicit "flush" after each I/O function call. Consequently, all four characters appear immediately when they are written to std::cout. No delay at all!
If, on the other hand, we pass the output of program.exe through test.exe, so that the stdout of the program.exe is connected to a pipe (rather than a TTY), then the default buffering is in effect! Consequently, neither "A" or "B" show up, until they are flushed together with "C". Also "D" is flushed immediately.
When a program begins execution, the startup code automatically opens several streams: standard input (pointed to by stdin), standard output (pointed to by stdout), and standard error (pointed to by stderr). These streams are directed to the console (keyboard and screen) by default. [...] Files opened using the stream routines are buffered by default. The stdout and stderr functions are flushed whenever they are full or, if you are writing to a character device [i.e. TTY, i.e. terminal], after each library call.
I guess the buffering behaviour can differ slightly between different compilers or different systems.
You are right. I can reproduce line-buffering behavior on Linux system.
(The bahvior of GCC/MinGW is consistent with VC++ on the Windows platform, so this is probably a difference between glibc and MSVCRT, not a compiler thing)
I think we can force "Windows-like" behavior on Linux, if that is desired, in the following way:
1 2 3 4 5 6 7 8 9 10 11
#include <unistd.h>
#include <iostream>
int main()
{
if (isatty(fileno(stdout))) {
setvbuf(stdout, NULL, _IONBF, 0);
}
std::cout << "A";
sleep(10);
[...]
Also note the difference between writing \n and std::endl. std::endl will enforce a stream flush, whereas \n will not.
output streams are fully buffered if and only if they are referring to a non-interactive device. So for say a file, writing '\n' won't usually perform a specific flush whereas std::endl will. This could have a major performance impact when writing large files.
As std:;cout and std::cin are usually tied, all waiting console output is performed before input (ie flushed before input).
From the C standard (C++ follows this):
7.21.3 §3
When a stream is unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters may be accumulated and transmitted to or from the host environment as a block. When a stream is fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled. When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment. Support for these characteristics is implementation-defined, and may be affected via the setbuf and setvbuf functions.
7.21.3 §7
At program startup, three text streams are predefined and need not be opened explicitly — standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
C++ follows this (i/o operations on C++ standard streams are forwarded to their corresponding C counterparts) if synchronisation with standard C++ streams is not turned off with std::ios_base::sync_with_stdio(false). If it is turned off, buffering is enabled for the C++ standard streams, mixing C++ and C i/o may produce garbled results, and the C++ standard streams are not guaranteed to be thread-safe.
/* Buffer pointers for stdout and stderr */
void *_stdbuf[2] = { NULL, NULL};
/* if stdout/stderr is still unbuffered, buffer it */
int _stbuf(FILE *stream)
{
[...]
/* do nothing if not a tty device */if (!_isatty(_fileno(stream)))
return(0);
/* Make sure stream is stdout/stderr and init _stdbuf index */
if (stream == stdout)
index = 0;
elseif (stream == stderr)
index = 1;
elsereturn(0);
[...]
/* Allocate a buffer for this stream if we haven't done so yet. */
if ((_stdbuf[index] == NULL) && ((_stdbuf[index]=_malloc_crt(_INTERNAL_BUFSIZ)) == NULL)) {
/* Cannot allocate buffer */
[...]
}
else {
/* Set up the buffer */
stream->_ptr = stream->_base = _stdbuf[index];
stream->_cnt = stream->_bufsiz = _INTERNAL_BUFSIZ;
}
stream->_flag |= (_IOWRT | _IOYOURBUF | _IOFLRTN);
[...]
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* If stdout/stderr is being buffered and is a device, _flush and dismantle buffer. */
void _ftbuf(int flag, FILE *stream)
{
[...]
if (flag) {
if (stream->_flag & _IOFLRTN) {
/* Flush the stream and tear down temp buffering. */
_flush(stream);
stream->_flag &= ~(_IOYOURBUF | _IOFLRTN);
stream->_bufsiz = 0;
stream->_base = stream->_ptr = NULL;
}
}
}
So, in MSVCRT, if stdout or stderr is connected to a TTY, then the I/O function, e.g. fputs(), will set up a temporary buffer before the actual write, and it will also flush + remove that buffer before returning.
To determine if the standard C++ streams are synchronized with the standard C streams (to determine if i/o is to be forwarded to the C stream), microsoft appears to use a flag.
libc++, like the microsoft library, apparently uses a flag to indicate the flushing (forwarding to C stream) behaviour.
libstdc++ actually destroys the old stream buffer and creates a new one (with a different type) if the synchronization changes.