std::cout声明是如何工作的

How does std::cout declaration work?

本文关键字:工作 cout 声明 std 何工作      更新时间:2023-10-16

std::cout对象在iostream头文件中声明为

namespace std _GLIBCXX_VISIBILITY(default)
{
...
extern ostream cout;
...
}

从现在开始,我将去掉std::前缀。

因此,据我所知,cout"只是"ostream类型的对象。我开始想知道为什么东西是用cout打印到屏幕上,而不是用其他ostream对象,所以我试图创建一个类型为ostream的对象,但编译器不让我。事实上,ostream只是basic_ostream<char>的别名,并且该类型的默认构造函数是受保护的。好吧,我想。但后来我想知道:为什么宣布cout是合法的呢?为什么不会产生编译错误?

我再次尝试用关键字extern声明ostream,例如
extern ostream os;
os << "Will you compile?n";

,这次我得到了os的未定义引用错误。然后问题就转移到下面:在其他地方是否有cout的"定义"?如果有,在哪里?

我无法理解这个。我知道,出于性能和安全原因,标准头文件是以一种"神秘"的方式编写的,除非你完全掌握了这种语言(我仍然不太可能),否则并不总是容易阅读,但我想理解这一点。

谢谢。

我开始想知道为什么东西是用cout打印到屏幕上,而不是用其他ostream对象,

因为std::cout使用了一个与stdout设备相关联的流缓冲区

所以我尝试创建一个ostream类型的对象,但是编译器不允许。事实上,ostream只是basic_ostream的别名,该类型的默认构造函数是受保护的。好吧,我想。但后来我想知道:为什么一开始就宣布结婚是合法的?为什么不会产生编译错误?

因为它是声明,而不是定义,所以它不调用任何构造函数。也许你应该读一读extern在声明中的含义。

带有extern的声明只是表示在程序的其他地方定义了一个类型为ostream并称为cout的对象。由于您实际上没有提供任何这样的定义,因此您会得到链接器错误。

要近似模拟std::cout,您可以在某些.cpp文件中这样做:

namespace {
  std::ofstream fake_cout("/dev/stdout");
}
std::ostream cout(fake_cout.rdbuf());

创建一个写入/dev/stdoutfstream,然后将ostream(称为cout)与其流缓冲区关联。

这并不是对真正的std::cout的一个很好的模拟,因为它不能确保在任何其他全局变量尝试使用它之前对流进行初始化,而真正的全局变量是这样做的。

在其他地方有cout的"定义"吗?如果有,在哪里?

是的,在标准c++库的libstdc++实现中有cout的定义。这个定义在标准c++中是无效的。没关系,因为标准c++库的实现不一定要用标准c++编写,它只需要以实现的其余部分能够理解的方式编写即可。