Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Redirecting stdout and stderr

2,298 views
Skip to first unread message

Artist

unread,
Aug 14, 2002, 11:59:20 PM8/14/02
to
I need to redirect stdout and stderr to output to a string variable. I tried
redeclaring with:

std::stringstream *stdout, *stderr;

and got many errors. What is the right way to do it?

GBR

unread,
Aug 15, 2002, 3:31:01 AM8/15/02
to
you need to use a pipe. Search this forum, I posted an example some time
ago. You can also find an answer in MS Knowledge Base.

GB

"Artist" <Art...@sj.cwia.com> wrote in message
news:3D5B2718...@sj.cwia.com...

Chris Uzdavinis [TeamB]

unread,
Aug 15, 2002, 11:07:42 AM8/15/02
to
"GBR" <a...@127.0.0.1> writes:

> you need to use a pipe. Search this forum, I posted an example some time
> ago. You can also find an answer in MS Knowledge Base.

This is not true. You might be able to do it with pipes, but you
certainly don't need to. And MS Knowledge Base is worthless when
you're using other operating systems...

Simply replace the underlying streambuf that cout uses with one that
is created by a stringstream.

#include <iostream>
#include <sstream>

int main()
{
using namespace std;

// remember cout's old streambuf
streambuf * cout_strbuf(cout.rdbuf());

// create the new stream to "redirect" cout's output to
ostringstream output;

// set cout's streambuf to be the ostringstream's streambuf
cout.rdbuf(output.rdbuf());

// Now we're ready to go, everything's set up

// write something to cout... but it really goes to the
// stringstream
cout << "Hello there" << endl;

// show our results.
cerr << "our stringstream now contains: " << output.str();

// replace cout's original streambuf when we're done. It will
// crash otherwise, since cout and stringstream will both
// destroy the same streambuf. Not truly safe, since a return
// can bypass this call...
cout.rdbuf(cout_strbuf);
}

For a more robust solution, a local object should swap-out the
streambufs in the constructor, and swap them back in the destructor.
That way premature returning out of main will not cause an error.

#include <iostream>
#include <sstream>

int main()
{
using namespace std;

// create the new stream to "redirect" cout's output to
ostringstream output;

// smart class that will swap streambufs and replace them
// when object goes out of scope.
class StreamBuf_Swapper
{
public:
StreamBuf_Swapper(ostream & orig, ostream & replacement)
: buf_(orig.rdbuf()), str_(orig)
{ orig.rdbuf(replacement.rdbuf()); }
~StreamBuf_Swapper() { str_.rdbuf(buf_); }
private:
std::streambuf * buf_;
std::ostream & str_;
} swapper(cout, output);

// Now we're ready to go, everything's set up

// write something to cout... but it really goes to the
// stringstream
cout << "Hello there" << endl;

// show our results.
cerr << "our stringstream now contains: " << output.str();

// cleanup is automatically handled in all cases by swapper's
// destructor.
}

--
Chris(TeamB);

Chris Uzdavinis [TeamB]

unread,
Aug 16, 2002, 9:14:51 AM8/16/02
to
Artist <Art...@sj.cwia.com> writes:

> I have tried it. There is a problem. The relevant sections of code are:
>
> class redirectStream
> { public:
> redirectStream(std::ostream & stream, std::ostream & redirTo);
> ~redirectStream();


>
> private:
> std::streambuf * buf_;
> std::ostream & str_;

> };
>
> redirectStream::redirectStream(std::ostream & stream, std::ostream & redirTo)
> : str_(stream), buf_(stream.rdbuf())
> { stream->rdbuf(redirTo.rdbuf());
> }
> redirectStream::~redirectStream() { str_.rdbuf(buf_); }
> std::ostringstream errStr;
> redirectStream redErrStr( stderr, errStr ); //Error on this line
>
> The error:
> E2285 Could not find match for 'redirectStream::redirectStream( FILE*,
> ostringsrteam)'

The error message contains all the hints necessary. Argument 1 is a
FILE*, which is a C standard library type. You should be passing in
an ostream object. So look at the parameter being passed in...

redirectStream redErrStr( stderr, errStr ); //Error on this line

Whoops, stderr is a FILE*, but you don't want that. You meant to pass
in std::cerr, correct?

This isn't truly redirecting the data at the file-handle level, only
at the C++ object level. So if you write to file descriptor 2, for
example, it would still write to the standard-error "stream."

If you use C routines that work on FILE* types, then my solution won't
work either. But if you stick to the C++ types to encapsulate this,
then the streambuf swapper solution will work.

--
Chris(TeamB);

Artist

unread,
Aug 16, 2002, 3:51:51 PM8/16/02
to

Chris Uzdavinis [TeamB] wrote:


No.

I am integrating a large package written in C into a C++ program. To minimize
editing, and make convenient the integration of future upgrades of this C
package, I wanted to edit the C package as little as possible.

The C package contains many writes to stdout and stderr. Instead of editing
every fprintf() statement I had hoped to simply redirect stdout and stderr to a
variable, or stream with a buffer I can access.

If the C and C++ streams are synchronized with the statement

std::ios_base::sync_with_stdio(true);

they are using the same buffers. Will that mean redirecting cerr will also
redirect stdout?


> This isn't truly redirecting the data at the file-handle level, only
> at the C++ object level. So if you write to file descriptor 2, for
> example, it would still write to the standard-error "stream."
>
> If you use C routines that work on FILE* types, then my solution won't
> work either. But if you stick to the C++ types to encapsulate this,
> then the streambuf swapper solution will work.


Does this mean that what I trying to do also cannot be done with pipes?


--
If sj. appears in my email address remove it to respond.
It is a spam jammer.

Artist

unread,
Aug 17, 2002, 1:19:33 AM8/17/02
to
This is very close to what I want to do:

http://leunen.com/cbuilder/redirect.html

The only difference is I want stdout and stderr to end up in different
variables. This means, I think, different pipes. Can that be done?

Chris Uzdavinis [TeamB] wrote:

> I'm not sure. I've never tried using pipes to redirect stdio. My
> solution was swapping out a higher level, and that won't work since
> you need it at a lower level.
>
> The C++ standard doesn't talk about file descriptors, but some
> iostream implementations have ways to put a specific FD into an
> fstream and read from or write to the stream using that FD.
>
> Rogue Wave used to have such a language extension, but I am not sure
> if that's still there. You might be able to construct a streambuf
> from a file descriptor, and snap that streambuf into a stringstream.
>
> (But I don't have BCB to experiment with at the moment.)

0 new messages