[英]How is `std::cout` implemented?
std::cout
is an instance of std::ostream
. std::cout
是std::ostream
的一个实例。 I can see the declaration of std::cout
in a file named /usr/include/c++/7/iostream
:我可以在名为
/usr/include/c++/7/iostream
的文件中看到std::cout
的声明:
extern ostream cout; /// Linked to standard output
And std::ostream
is defined by typedef std::basic_ostream<char> std::ostream
. std::ostream
由typedef std::basic_ostream<char> std::ostream
定义。
What's more, it seems that you can't create an instance of std::ostream
.而且,您似乎无法创建
std::ostream
的实例。 See this demo code snippet :请参阅此演示代码片段:
#include<iostream>
int main()
{
std::ostream os;
return 0;
}
Here is what the compiler complains about the code snippet above:以下是编译器对上面代码片段的抱怨:
In file included from /opt/compiler-explorer/gcc-4.9.0/include/c++/4.9.0/iostream:39:0,
from <source>:1:
/opt/compiler-explorer/gcc-4.9.0/include/c++/4.9.0/ostream: In function 'int main()':
/opt/compiler-explorer/gcc-4.9.0/include/c++/4.9.0/ostream:384:7: error: 'std::basic_ostream<_CharT, _Traits>::basic_ostream() [with _CharT = char; _Traits = std::char_traits<char>]' is protected
basic_ostream()
^
<source>:5:18: error: within this context
std::ostream os;
^
The question arises, since the std::basic_ostream<_CharT, _Traits>::basic_ostream()
is marked protected, how std::cout
is created?问题出现了,因为
std::basic_ostream<_CharT, _Traits>::basic_ostream()
被标记为受保护, std::cout
是如何创建的?
This link on CppReference seems not very meaningful. CppReference 上的这个链接似乎意义不大。 It does not clearly tell me how
std::cout
is implemented and how std::cout
is created by the constructor of std::ostream
.它没有清楚地告诉我
std::cout
是如何实现的,以及std::cout
是如何由std::ostream
的构造函数创建的。 As far as I can see, the most related information is:据我所知,最相关的信息是:
The global objects
std::cout
andstd::wcout
control output to a stream buffer of implementation-defined type (derived fromstd::streambuf
), associated with the standard C output streamstdout
.全局对象
std::cout
和std::wcout
控制 output 到实现定义类型的 stream 缓冲区(派生自std::streambuf
),与标准 C output streamstdout
关联。
And nothing more.仅此而已。
I am working on Ubuntu
with gcc 4.9
我正在使用
Ubuntu
和gcc 4.9
Thanks to @NathanPierson.感谢@NathanPierson。
He told me that他告诉我
std::basic_ostream
has a constructor that takes a pointer to astd::basic_streambuf
object.std::cout
is initialized using a pointer to an instance of some implementation-defined derived class ofstd::basic_streambuf
.std::basic_ostream
有一个构造函数,该构造函数采用指向std::basic_streambuf
object 的指针。stdstd::cout
使用指向std::basic_streambuf
的某个实现定义的派生 class 的实例的指针进行初始化。
, which moves me closer to the answer. ,这让我离答案更近了。
how std::cout is created?
std::cout 是如何创建的?
First things first, from https://en.cppreference.com/w/cpp/io/ios_base/Init :首先,来自https://en.cppreference.com/w/cpp/io/ios_base/Init :
std::ios_base::Init
std::ios_base::Init
This class is used to ensure that the default C++ streams (std::cin, std::cout, etc.) are properly initialized and destructed.
此类用于确保默认 C++ 流(std::cin、std::cout 等)正确初始化和销毁。 [...]
[...]
The header
<iostream>
behaves as if it defines (directly or indirectly) an instance of std::ios_base::Init with static storage duration: [...]标头
<iostream>
的行为就好像它(直接或间接)定义了一个具有静态存储持续时间的 std::ios_base::Init 实例:[...]
Meh, let's do a real code example.嗯,让我们做一个真实的代码示例。 I will be using GCC C++ library .
我将使用GCC C++ 库。 From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/iostream#L73 , this is the important part:
从https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/iostream#L73 ,这是重要的部分:
// For construction of filebuffers for cout, cin, cerr, clog et. al.
static ios_base::Init __ioinit;
Now we jump to the constructor of ios_base::Init
class, in https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc#L85 :现在我们跳转到
ios_base::Init
类的构造函数,在https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init。抄送#L85 :
ios_base::Init::Init()
{
if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 1) == 0)
{
// Standard streams default to synced with "C" operations.
_S_synced_with_stdio = true;
new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout);
new (&buf_cin_sync) stdio_sync_filebuf<char>(stdin);
new (&buf_cerr_sync) stdio_sync_filebuf<char>(stderr);
// The standard streams are constructed once only and never
// destroyed.
new (&cout) ostream(&buf_cout_sync);
new (&cin) istream(&buf_cin_sync);
new (&cerr) ostream(&buf_cerr_sync);
new (&clog) ostream(&buf_cerr_sync);
cin.tie(&cout);
cerr.setf(ios_base::unitbuf);
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 455. cerr::tie() and wcerr::tie() are overspecified.
cerr.tie(&cout);
The _S_refcount
is there for when you would call ios_base::Init::Init();
_S_refcount
用于您何时调用ios_base::Init::Init();
manually from a constructor of a static class, it protects against double initialization.从静态类的构造函数手动,它可以防止双重初始化。
The stdio_sync_filebuf
is an internal buffer for istream
/ ostream
and it is meant to handle cstdio
FILE*
operations to get/put input/output data, with implementation here https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/ext/stdio_sync_filebuf.h#L56 . stdio_sync_filebuf
是istream
/ ostream
的内部缓冲区,它旨在处理cstdio
FILE*
操作以获取/放置输入/输出数据,在此处实现https://github.com/gcc-mirror/gcc/blob/master/ libstdc%2B%2B-v3/include/ext/stdio_sync_filebuf.h#L56 。 It inherits from std::basic_streambuf
.它继承自
std::basic_streambuf
。
So cout
is constructed in-place with stdio_sync_filebuf<char>
as parameter.所以
cout
是用stdio_sync_filebuf<char>
作为参数就地构造的。 It is the first constructor mentioned here https://en.cppreference.com/w/cpp/io/basic_ostream/basic_ostream .这是这里提到的第一个构造函数https://en.cppreference.com/w/cpp/io/basic_ostream/basic_ostream 。
Now, because the stuff is constructed in-place, you might wonder how is the memory allocated?现在,因为这些东西是就地构建的,你可能想知道内存是如何分配的? From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/globals_io.cc#L50 :
从https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/globals_io.cc#L50 :
// Standard stream objects.
// NB: Iff <iostream> is included, these definitions become wonky.
typedef char fake_istream[sizeof(istream)]
__attribute__ ((aligned(__alignof__(istream))));
typedef char fake_ostream[sizeof(ostream)]
__attribute__ ((aligned(__alignof__(ostream))));
fake_istream cin;
fake_ostream cout;
fake_ostream cerr;
fake_ostream clog;
The objects are just empty char
buffers of proper size and proper alignment.这些对象只是适当大小和适当对齐的空
char
缓冲区。
And yes, you can construct ostream yourself, with __gnu_cxx::stdio_sync_filebuf
on GCC:是的,您可以自己构建 ostream,在 GCC 上使用
__gnu_cxx::stdio_sync_filebuf
:
#include <fstream>
#include <ext/stdio_sync_filebuf.h>
int main() {
__gnu_cxx::stdio_sync_filebuf<char> mybuf_cout_sync(stdout);
std::ostream os(&mybuf_cout_sync);
os << "Hello world!\n";
return 0;
}
Or, to be portable, you would write your own class that inherits from std::streambuf
and construct ostream
from it yourself.或者,为了便于移植,您可以编写自己的类,该类继承自
std::streambuf
并自己从中构造ostream
。 There are many examples online, like for example here https://stackoverflow.com/a/51250032/9072753 .网上有很多例子,例如这里https://stackoverflow.com/a/51250032/9072753 。
A compiler and its standard library implementation may cooperate using non-standard features which are not usable by mere programmers.编译器及其标准库实现可以使用非标准功能进行协作,这些功能仅由程序员使用。
This is not necessary in this case because there is a quite standard public constructor:在这种情况下这不是必需的,因为有一个非常标准的公共构造函数:
explicit basic_ostream(basic_streambuf<char_type, Traits>* sb);
If you have a streambuf
ready, you can create an object of type ostream
, and so can the standard library.如果您准备好
streambuf
,则可以创建ostream
类型的对象,标准库也可以。
What is that streambuf
exactly is a hidden implementation detail, but on a typical implementation it is probably an object of a custom class constructed from stdout
(the C-style <cstdio>
file pointer).那个
streambuf
究竟是一个隐藏的实现细节,但在典型的实现中,它可能是从stdout
(C风格的<cstdio>
文件指针)构造的自定义类的对象。
I think a part of what the current answers are missing, and what is part of your question:我认为当前答案的一部分缺失,以及您的问题的一部分:
the name std::cout
is also 'magical'. std::cout
这个名字也是“神奇的”。
This means that the standard library knows about it, and provides the OS-specific necessary connections to the terminal;这意味着标准库知道它,并为终端提供特定于操作系统的必要连接; using the respective (and OS-specific) system calls for output, etc.
使用相应的(和特定于操作系统的)系统调用进行输出等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.