为啥我们需要绑定 std::cin 和 std::cout?
Posted
技术标签:
【中文标题】为啥我们需要绑定 std::cin 和 std::cout?【英文标题】:Why do we need to tie std::cin and std::cout?为什么我们需要绑定 std::cin 和 std::cout? 【发布时间】:2012-12-27 09:50:56 【问题描述】:默认情况下,标准输入设备与标准输出设备绑定在一起,形式如下:
std::cin.tie (&std::cout);
保证在调用输入之前已刷新输出缓冲区。于是我尝试用std::cin.tie(0)
解开它们,但结果似乎和被绑的没有区别。
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
char c;
cin.tie(0)
cout << "Please enter c:";
cin >> c;
cout << c ;
return 0;
我测试错了吗?为什么我们需要将它们捆绑在一起?它们共享同一个缓冲区吗?
【问题讨论】:
领带背后的想法是在阅读输入之前应该显示提示。 :-) 【参考方案1】:您的示例没有任何问题(除了您应该在cin.tie(0)
行之后添加一个分号),也没有 iostream 对象的工作方式。
tie()
只是保证在cin
执行输入之前刷新cout
。这对于用户在被要求回答之前查看问题很有用。
但是,如果您从cout
中取消tie()
cin
,则不能保证cout
的缓冲区会被刷新。但是不能保证缓冲区也不会被刷新。事实上,如果计算机有足够的资源,它会立即刷新cout
缓冲区,所以这发生在cin
请求输入之前。您的示例就是这种情况。
所以,一切正常。除了cin.tie(0)
之后,不保证会发生刷新。但是,在 99% 的情况下,这种刷新仍然会发生(但不再保证)。
理论上,如果绑定,cin
和 cout
可以共享同一个缓冲区。但是,我认为没有任何实现可以做到这一点。一个原因是这两者可能是 un-tie()d。
【讨论】:
次要的挑剔:如果(streambuf
底层)cin
必须向环境询问更多输入,则平局仅保证 cout
将刷新。如果cin
的输入缓冲区包含足够的数据来满足读取请求,您将不会获得刷新。
挑剔第二个:cout
在示例代码中被刷新的原因与“资源”无关——这是因为默认情况下启用了与 stdio 的同步,因此刷新是由 stdio 的策略发生的。在(交互式)Windows 环境中,默认情况下,stdio 输出流是完全无缓冲的,因此输出会立即发生。 (linux在这种情况下更喜欢行缓冲,所以示例代码不会刷新,除非缓冲区太小以至于提示填满它)【参考方案2】:
我认为,之前的答案是错误的(我想知道为什么它如此受欢迎并被标记为真实,但显然不是)。
要打破happens-before tie,你应该(仅在标准io的情况下)(1)删除与stdio的同步和(2)解开流。
像这样:
std::cin.tie (nullptr);
std::cout.sync_with_stdio(false);
std::cout << "Please enter c: ";
std::cin >> c;
那么您就保证拥有未绑定的流。与 stdio 同步是一种特殊功能,可以在 C 样式和 C++ 样式的输入和输出的排序后进行正确的发生,我强烈建议您不要在没有真正必要的情况下将其删除。
【讨论】:
执行代码后仍然得到Please enter c:
。
检查 std::cout 是否正确缓冲。如果它是无缓冲的,您将立即打印任何字符。
我该怎么做?
基本上 rdbuf 应返回非 null 且 unitbuf 标志不应在 flags 中设置【参考方案3】:
在 C 中,提示用户输入的模式遵循您发出命令以打印提示消息,然后发出命令以输入值的模式。
为了让这个过程正常工作,你需要确保提示信息是真实显示的。环境已配置为自动进行:
在 DOS(或 windows 命令行)环境中,STDOUT
是无缓冲的,因此打印命令会立即显示消息。
在 *NIX 环境中,STDOUT
是行缓冲的。因此,如果您遵循 *NIX 风格,在提示消息中包含换行符,以便用户在下一行输入输入,您的提示将在输入之前自动显示。
tie 特性使这种自动刷新行为成为 iostream 库工作方式的一部分,而不是约定俗成的产物。 (但请注意,自动刷新仅在程序要求系统获取更多输入时发生,因此存在cin >> c
不会实际刷新的极端情况)
但是!默认情况下,iostream 库与 stdio 库同步。实际上,这意味着 iostream 根本不做任何缓冲。它只是将数据转发到底层 C 库。
因此,这意味着您看到的内容与编写类似 C 程序时通常看到的内容相同。如果您在 windows 命令行环境中,输出不会被缓冲,因此您会在输入之前看到提示。
要查看本机 C++ 行为,您需要通过在程序开始时运行 std::cout.sync_with_stdio(false);
来关闭同步,如 the other answer 中所示。
如果你这样做,那么cout
语句将不会刷新输出缓冲区(除非缓冲区非常小)。并且由于您已经移除了领带,cin
语句也不会刷新它。因此,您将获得必须在看到提示之前输入用户输入的结果。
【讨论】:
以上是关于为啥我们需要绑定 std::cin 和 std::cout?的主要内容,如果未能解决你的问题,请参考以下文章