在更改文件描述符1以引用不同的文件后,我应该如何管理:: std :: cout?

时间:2017-10-17 20:45:04

标签: c++ iostream file-descriptor

我想dup2(fd, 1); close(fd);::std::cout写入新的fd 1.我怎样才能重置::std::cout的状态,这样什么都不好笑?例如,预先冲洗是否足够?或者还有更多事要做吗?

我也对::std::cin同样感到好奇。

如果您更改了他们在其下面使用的文件描述符,是否有重置这些的标准机制?

要明确,我的目标基本上是将我自己的输入和输出重定向到其他地方。我希望不要让这个过程无意中在父母的stdout上烧掉一些东西,或者试图从它的父母的stdin中消费掉任何东西。而且我再也不想触摸父母的stdin或stdout了。我想忘记他们曾经存在过。

我最特别不想无意中将输出发送到我父母在不同文件描述符上使用的同一设备。

我的目标是让cin和cout导致与过程开始时完全不同的地方,并且永远不会以任何方式触及他们过去所处的地方。永远!

2 个答案:

答案 0 :(得分:4)

选项1:设置stdin&标准输出

根据cppreference.com

  

默认情况下,所有八个标准C ++流都与其各自的C流同步。

只要您没有明确调用sync_with_stdio(false),他们就会保持这种状态。这是什么意思?以下内容:

  

实际上,这意味着同步的C ++流是无缓冲的,并且C ++流上的每个I / O操作都会立即应用于相应的C流缓冲区。这使得可以自由地混合C ++和C I / O.

所以,flush() - 你的cin&在cout dup()之前if (freopen("input.txt", "r", stdin) == NULL) { // Handle error, errno is set to indicate error } if (freopen("output.txt", "w", stdout) == NULL) { // Handle error, errno is set to indicate error } 应该足够了,因为它们应该处于一致的状态。

如果您希望使用文件,例如,您可以使用:

extern FILE * stdin

注1:设置全局stdoutFILE无法正常工作,因为它只是将指针的单个实例更改为相关的{{1} os的结构。在此更改之前的任何时刻复制此指针的任何模块将继续使用旧的FILE。一个具体的例子是libc ++对cout的实现,它在对象的init期间将FILE * stdout复制到私有成员。另一方面,freopen更改操作系统的内部FILE结构以使用新打开的文件,从而影响对FILE *dup()的任何人。

注2:使用freopen()个风格(而不是fd)时,我们正在更改基础FILE*,而不是freopen()dup()方法不止于此。来自POSIX

  

freopen()函数应首先尝试刷新与流相关的流,就好像通过调用fflush(stream)一样。无法成功刷新流将被忽略。如果pathname不是空指针,则freopen()将关闭与stream关联的任何文件描述符。无法成功关闭文件描述符将被忽略。应清除流的错误和文件结束指示符。

freopen - 可能工作,,它可能棘手,因为它won't affect other properties of the FILE*,包括:字符宽度,缓冲状态,缓冲区,I / O,二进制/文本模式指示符,文件结束状态指示符,错误状态指示符,文件位置指示符& (在C ++之后17)用于防止数据竞争的重入锁定。

如果可能,我建议使用fflush()。否则,您可以按照自己描述的步骤进行操作(clearerr()fclose())。跳过FILE将是明智的,因为我们无法通过任何API方法重新打开相同的内部cin

选项2:设置cin& s& cout' s rdbuf()

反过来,就像提出的一些意见一样,正在使用cout替换rdbuf()ifstream的基础缓冲区。

您有什么选择?

  • 文件流:打开ofstream& std::ifstream fin("input.txt"); if (!fin) { // Handle error } cin.rdbuf(fin.rdbuf()); std::ofstream fout("output.txt"); if (!fout) { // Handle error } cout.rdbuf(fout.rdbuf()); 并使用它们:

    boost::asio::ip::tcp::iostream
  • 网络流:使用提升std::streambuf(它来自boost::asio::ip::tcp::iostream stream("www.boost.org", "http"); if (!stream) { // Handle error } cin.rdbuf(stream.rdbuf()); cout.rdbuf(stream.rdbuf()); // GET request example cout << "GET /LICENSE_1_0.txt HTTP/1.0\r\n"; cout << "Host: www.boost.org\r\n"; cout << "Accept: */*\r\n"; cout << "Connection: close\r\n\r\n"; cout.flush(); std::string response; std::getline(cin, response); ,因此可以使用):

    std::streambuf
  • 自定义流:使用您自己的^\(\d{3}\)\s{0,}\d{3}\s{0,}-\s{0,}\d{4}$自定义包装器。查看示例here

答案 1 :(得分:2)

您可以为socket_streambuf类创建(或使用现有的)库,并将其与std :: cout / std :: cin关联:

ConnectionString connect = new ConnectionString("","","");
Console.WriteLine("connection string: " + connect.password);

这样,您就不必费心去操纵(全局)C-stream缓冲区的状态。