C++ std::cout声明是如何工作的?
C++ std::cout声明是如何工作的?,c++,cout,C++,Cout,std::cout对象在iostream头文件中声明为 namespace std _GLIBCXX_VISIBILITY(default) { ... extern ostream cout; ... } 从现在起,我将删除std::前缀 因此,据我所知,cout只是一个类型为ostream的对象。我开始想知道为什么东西是用cout打印到屏幕上的,而不是用其他ostream对象,所以我尝试创建一个ostream类型的对象,但编译器不让我这样做。事实上,ostream只是basic\u ost
std::cout
对象在iostream
头文件中声明为
namespace std _GLIBCXX_VISIBILITY(default)
{
...
extern ostream cout;
...
}
从现在起,我将删除std::
前缀
因此,据我所知,cout
只是一个类型为ostream
的对象。我开始想知道为什么东西是用cout
打印到屏幕上的,而不是用其他ostream
对象,所以我尝试创建一个ostream
类型的对象,但编译器不让我这样做。事实上,ostream
只是basic\u ostream
的别名,该类型的默认构造函数受到保护。很好,我想。但接着我想知道:为什么一开始就声明cout
是合法的?为什么这不会导致编译器错误
我再次尝试使用关键字extern
声明一个ostream
,例如
extern ostream os;
os << "Will you compile?\n";
extern-ostream操作系统;
操作系统
我开始想知道为什么东西是用cout而不是其他ostream对象打印到屏幕上的
因为std::cout
使用与stdout
设备关联的流缓冲区
所以我尝试创建一个类型为ostream的对象,但编译器不允许。事实上,ostream只是basic_ostream的别名,该类型的默认构造函数受到保护。很好,我想。但后来我想知道:为什么cout的声明一开始就合法?为什么这不会导致编译器错误
因为它是一个声明,而不是一个定义,所以它不调用任何构造函数。也许你应该读一下extern
在声明中的含义
带有extern
的声明只表示程序中其他地方定义了一个对象,该对象的类型为ostream
,名为cout
。由于您实际上没有提供任何此类定义,因此会出现链接器错误
要大致模拟std::cout
,可以在一些.cpp
文件中执行此操作:
namespace {
std::ofstream fake_cout("/dev/stdout");
}
std::ostream cout(fake_cout.rdbuf());
这将创建一个写入/dev/stdout
的fstream
,然后将名为cout
的ostream
与其流缓冲区相关联
这不是对realstd::cout
的很好的模拟,因为它不能确保流在任何其他全局成员尝试使用它之前被初始化,而real确实是这样做的
在其他地方有cout的“定义”吗?如果是,在哪里
<>是,在标准C++库的LIbSTDC++中实现了<代码> CUT/COD>的定义。这个定义不是用标准C++中有效的方式来完成的。没关系,因为标准C++库的实现不必用标准C++编写,它只需要以其他实现方式来编写。你到底在哪里定义了操作系统ῥεῖ 没有,因此问题中提到了链接器错误。extern
关键字意味着问题中的变量是在别处定义的,编译器在链接之前不需要担心在哪里。所以,要回答“在别的地方有没有对cout的定义?”是的,肯定有。是的,我只是在黑暗中徘徊。但是我猜,cout
是在其他地方定义的……虽然在哪里?@bartgol它提供了lstdc++
,它是自动链接的。谢谢!我确实想知道定义在哪里,因为它不在C++包含文件夹中,所有标准头都在这里。但它是有意义的:它在标准头中声明,在源代码(即libstdc++库)中定义,在源代码中使用操作系统的缓冲区创建。现在清楚了。我忽略了一个事实,即std库不仅具有标题,而且还具有…一个库!=)谢谢你的例子!出于某种原因,我不认为cout的定义在某些源代码(或库)中,而不是在标题中。我当然找不到了!您的示例非常有用,因为它还让我在/dev文件夹中发现了stdout/err/in(我还需要学习很多关于unix系统和根目录树的知识)。谢谢另外,为什么std::cout
保证在任何其他全局函数尝试使用它之前初始化流,而我的个人实现不会?因为不同对象中全局函数的初始化顺序未指定,请参阅标准库采取特殊预防措施以确保std::cin
,std::cout
和std::cerr
在尝试使用它们的对象(通常使用。