Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Redirecting STDOUT

Tags:

c++

In my application, I want to redirect the output that would normally go to the stdout stream to a function I define. I read that you can redirect stdio to a file, so why not to a function?

For example:

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 
  • How can I achieve this / similar behaviour?
like image 431
Charx Avatar asked Jan 26 '11 21:01

Charx


People also ask

How to redirect stdout?

Redirecting stdout and stderr to a file: The I/O streams can be redirected by putting the n> operator in use, where n is the file descriptor number. For redirecting stdout, we use “1>” and for stderr, “2>” is added as an operator.

What is dup2 used for?

The dup2() system function is used to create a copy of an existing file descriptor. In Linux, there are 3 standard file descriptors. They are: stdin: This is the standard input file descriptor.

Which symbol should I use to redirect the standard output to a file overwrite the file)?

The command | tee file pattern (which includes the tee command) redirects the standard output of the command to a file and overwrites its contents. Then, it displays the redirected output in the terminal.


2 Answers

@Konrad Rudolph is right, you can totally do this, easily, at least for cout/cerr/clog. You don't even need your own streambuf implementation, just use an 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(); 

Same thing works for cerr and clog, but in my experience that will NOT work for stdout/stderr in general, so printf won't output there. cout goes to stdout, but redirecting cout will not redirect all stdout. At least, that was my experience.

If the amount of data is expected to be small, the freopen/setbuf thing works fine. I ended up doing the fancier dup/dup2 thing redirecting to a pipe.

Update: I wrote a blog post showing the dup2 method I ended up using, which you can read here. It's written for OS X, but might work in other Unix flavors. I seriously doubt it would work in Windows. Cocoa version of the same thing here.

like image 78
zpasternack Avatar answered Sep 20 '22 20:09

zpasternack


All the other answers are wrong. You can do this, and you don’t need to resort to freopen, nor to any other C or nonstandard functions.

Instead, you need to create your own std::streambuf implementation, i.e. your own stream buffer.

Once you have that, you can redirect the cout stream by switching the buffer:

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); 

Since I’ve never done that myself I cannot tell you exactly how the implementation of streambuf has to look like. My advice is to have a look at the documentation and do a dummy implementation that prints diagnostics for all implemented functions. This should help figuring out how the class works.

Alternatively, have a look at a C++ reference book of your choice that describes the streambuf class.

like image 42
Konrad Rudolph Avatar answered Sep 20 '22 20:09

Konrad Rudolph