C ++:redirectSTDOUT

在我的应用程序中,我想将通常会转到标准输出stream的输出redirect到我定义的函数。 我读过,你可以redirectstdio到一个文件,所以为什么不一个函数?

例如:

void MyHandler( const char* data ); //<<Magical redirection code>> printf( "test" ); std::cout << "test" << std::endl; //MyHandler should have been called with "test" twice, at this point 
  • 我怎样才能做到这一点/类似的行为?

@Konrad Rudolph是对的,你完全可以做到这一点,至less对于cout / cerr / clog来说很简单。 你甚至不需要你自己的streambuf实现,只需要使用ostringstream。

 // Redirect cout. streambuf* oldCoutStreamBuf = cout.rdbuf(); ostringstream strCout; cout.rdbuf( strCout.rdbuf() ); // This goes to the string stream. cout << "Hello, World!" << endl; // Restore old cout. cout.rdbuf( oldCoutStreamBuf ); // Will output our Hello World! from above. cout << strCout.str(); 

同样的事情对于cerr和clog是有效的,但是根据我的经验,一般来说stdout / stderr将不起作用,所以printf将不会在那里输出。 cout去标准输出,但redirectcout不会redirect所有的标准输出。 至less,那是我的经验。

如果数据量预计会很小,那么freopen / setbuf工作正常。 我结束了做fancier dup / dup2redirect到一个pipe道的事情。

更新:我写了一篇博客文章,展示了我最终使用的dup2方法,你可以在这里阅读。 它是为OS X编写的,但可能适用于其他Unix版本。 我严重怀疑它会在Windows中工作。 这里的cocoa版本是一样的东西。

所有其他答案都是错误的。 你可以做到这一点,你不需要诉诸freopen ,也不需要任何其他C或非标准function。

相反,你需要创build自己的std::streambuf实现,也就是你自己的stream缓冲区。

一旦你有了,你可以通过切换缓冲区来redirectcoutstream:

 your_stream_buffer new_buffer; streambuf* old_buffer = cout.rdbuf(&new_buffer); cout << "Hello"; // This will be redirected to `new_buffer`. // Restore original buffer: cout.rdbuf(old_buffer); 

由于我自己从来没有这样做过,所以我不能确切地告诉你streambuf的实现是怎么样的。 我的build议是看看文档,并做一个虚拟的实现,打印所有实现的function的诊断。 这应该有助于弄清楚这个class是如何工作的。

或者,看一看你所select的描述streambuf类的C ++参考手册。

答:是的,你可以通过一个dup。 正如你所说的,freopen只会重新打开stdout到一个文件。

检出如何缓冲内存中的标准输出并从专用线程写入

std::cout对象有一个固定的含义,那就是输出到标准输出stream。 您的程序的用户可以控制标准输出连接的位置,而不是您。 你可以做的是决定你是否希望写入文件,标准输出或任何其他输出stream。 所以在你的代码中你可以切换你写的stream。

同样,写入标准输出stream的点也是让用户能够灵活地select输出的位置。 你不应该redirect标准, 这是用户应该有自由做的事情。

另一件事是你不应该在C ++程序中混合使用C IO和C ++ IO。 select你想要的IO库并坚持下去。

也就是说,你可以在C ++中通过在std::basic_istream<>的模板参数上模板处理函数来优雅地切换一个函数的stream。 然后,函数将从inputstream中读取其input,而不依赖于正在处理的实际types的stream。 这是一个例子:

 #include<iostream> #include<fstream> #include<string> template<class Ch, class Tr> void dodge_this(std::basic_istream<Ch, Tr>& in) { // in is an input stream. read from it as you read from std::cin. } int main(int argc, char* argv[]) { if( std::string(argv[1]) == "cin" ) { dodge_this(std::cin); } else if( std::string(argv[1]) == "file" ) { std::ifstream file("input.txt"); dodge_this(file); } else { dodge_this(dev_null_stream); // i just made that up. you get the idea. } } 

可以通过取消引用其指针来禁用stdin / stdout:

 FILE fp_old = *stdout; // preserve the original stdout *stdout = *fopen("/dev/null","w"); // redirect stdout to null HObject m_ObjPOS = NewLibraryObject(); // call some library which prints unwanted stdout *stdout=fp_old; // restore stdout 

以下不是最好的实现,但它应该适用于大多数输出​​…

 using std::cout; using std::endl; using std::string; using std::stringstream; class Handler { public: Handler() { }; virtual ~Handler() { }; void operator<<(string str) { this->stream << str; }; string print(void) { return this->stream.str(); } private: stringstream stream; }; int main(int argc, char ** argv) { Handler handle; handle << argv[1]; cout << handle.print() << endl; return 0; } 

我只是把一个小的主要function放在下面,让你试试看它是否按照你想要的方式工作。

您可以使用sprintf写入字符数组,然后读取值:

 char buf[1024]; sprintf(buf, "test"); MyHandler(buf); 

也有snprintf和一些其他的取决于平台