Okay, here's what I've found.
Actually, the I/O is ultimately performed by native system calls and functions.
Now, take Microsoft Windows for example. There are actually available handles for STDIN
, STDIO
etc (see here). So basically, both the C++ iostream
and C stdio
call native system functions, the C++ iostream
does not wrap C's I/O functions (in modern implementations). It calls the native system methods directly.
Also, I found this:
Once stdin, stdout, and stderr are redirected, standard C functions such as printf() and gets() can be used, without change, to communicate with the Win32 console. But what about C++ I/O streams? Since cin, cout, cerr, and clog are closely tied to C’s stdin, stdout, and stderr, you would expect them to behave similarly. This is half right.
C++ I/O streams actually come in two flavors: template and non- template. The older non-template version of I/O streams is slowly being replaced by a newer template style of streams first defined by the Standard Template Library (STL) and which are now being absorbed into the ANSI C++ standard. Visual C++ v5 provides both types and allows you to choose between the two by including different header files. STL I/O streams work as you would expect, automatically using any newly redirected stdio handles. Non-template I/O streams, however, do not work as expected. To discover why, I looked at the source code, conveniently provided on the Visual C++ CD-ROM.
The problem is that the older I/O streams were designed to use UNIX-style "file descriptors," where integers are used instead of handles (0 for stdin, 1 for stdout, and so on). That’s convenient for UNIX implementations, but Win32 C compilers have to provide yet another I/O layer to represent that style of I/O, since Win32 does not provide a compatible set of functions. In any case, when you call _open_osfhandle() to associate a new Win32 handle with (for example) stdout, it has no effect on the other layer of I/O code. Hence, file descriptor 1 will continue using the same underlying Win32 handle as before, and sending output to cout will not produce the desired effect.
Fortunately, the designers of the original I/O stream package foresaw this problem and provided a clean and useful solution. The base class ios provides a static function, sync_with_stdio(), that causes the library to change its underlying file descriptors to reflect any changes in the standard I/O layer. Though this is not strictly necessary for STL I/O streams, it does no harm and lets me write code that works correctly with either the new or old form of I/O streams.
(source)
Hence calling sync_with_stdio()
actually changes the underlying file descriptors. It was in fact added by the designers to ensure compatibility of the older C++ I/O with systems like Windows-32 which used handles instead of integers.
Note that Using sync_with_stdio()
is not necessary with modern C++ template-based STL I/O.