Redirect COUT to file

O

Omid

Hi.

I have problems when I try to redirect everything that is sent to cout
to a file.
I have one piece of code that works and one that does not work.
The only difference is which headers I use.


What the code does:
* First writes "This is sent to prompt" to prompt.
* Then writes "This is sent to file" to file (test.txt).
* Then writes "This is also sent to prompt" to prompt.

Code that works:
##########################################
#include <iostream>
#include <fstream>
using namespace std;

int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
##########################################


Code that DOES NOT work:
##########################################
#include <iostream.h>
#include <fstream.h>

int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf()); //ERROR C2660: function does not take 1
parameters
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf); //ERROR C2660: function does not take 1 parameters
cout << "This is also sent to prompt" << endl;
return 0;
}
##########################################

As you can see the only lines that differs are the first 3 lines in
each file.

The error I get is:
andracout.cpp
andracout.cpp(10) : error C2660: 'rdbuf' : function does not take 1
parameters
andracout.cpp(12) : error C2660: 'rdbuf' : function does not take 1
parameters


I compile with:
cl.exe /GX /TP andracout.cpp

cl.exe = Microsoft (R) 32-bit C/C++ Optimizing Compiler Version
12.00.8168 for 80x86
/GX[-] = enable C++ EH (same as /EHsc)
/TP = compile all files as .cpp


Can someone please tell me how to make my code work also with the old
headers.

Now you might ask why I don't just stick with the code that works.

Short explanation why it must work with the old headers:
I can't use the new headers (<iostream> and <fstream>).
I must use the old headers (<iostream.h> and <fstream.h>).

Longer explanation:
The reason why I can't use the new headers (which works in my example)
is that I use a program (ADS from Agilent) that generates all
C++-code. I only give a piece of code to ADS and it will include the
code in some function in a large and complex .cc-file which it will
then compile by automatic, and I can't change the headers it uses.


My problem would be solved if someone could tell me how I can switch
this line in my code:
cout.rdbuf(sbuf);

....to some other piece of code that does the same thing but that does
not use "streambuf* ios::rdbuf ( streambuf* sb );", since it seems
that it is not defined in the .h-files.


I would be very thankful for any information that can help me solve my
problem.

Also, while I have been looking for a solution to my problem I came
across this piece of text that was found in the "basic_ios.h"-file
under my Cygwin-directory. I don't know if this is relevant for me,
but I strongly sense that it is related to my problem:

From "C:\cygwin\usr\include\c++\3.3.1\bits\basic_ios.h":
#########################################
/**
* @brief Accessing the underlying buffer.
* @return The current stream buffer.
*
* This does not change the state of the stream.
*/
basic_streambuf<_CharT, _Traits>*
rdbuf() const
{ return _M_streambuf; }

/**
* @brief Changing the underlying buffer.
* @param sb The new stream buffer.
* @return The previous stream buffer.
*
* Associates a new buffer with the current stream, and clears
the
* error state.
*
* Due to historical accidents which the LWG refuses to
correct, the
* I/O library suffers from a design error: this function is
hidden
* in derived classes by overrides of the zero-argument @c
rdbuf(),
* which is non-virtual for hysterical raisins. As a result,
you
* must use explicit qualifications to access this function via
any
* derived class.
*/
basic_streambuf<_CharT, _Traits>*
rdbuf(basic_streambuf<_CharT, _Traits>* __sb);
#########################################


Can anyone see why I get the error I get and how I can avoid it and
still be using the ".h-headers".


Best Regards
/Omid
 
T

tom_usenet

Hi.

I have problems when I try to redirect everything that is sent to cout
to a file.
I have one piece of code that works and one that does not work.
The only difference is which headers I use.
Code that DOES NOT work:
##########################################
#include <iostream.h>
#include <fstream.h>

My compiler (VC 7.1) doesn't have this header at all, so just so you
know, any fix is only temporary; if you upgrade, you're doomed. Fewer
and fewer compilers support any kind of legacy IOstreams...
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf()); //ERROR C2660: function does not take 1
parameters
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf); //ERROR C2660: function does not take 1 parameters
cout << "This is also sent to prompt" << endl;
return 0;
}
##########################################

cl.exe = Microsoft (R) 32-bit C/C++ Optimizing Compiler Version
12.00.8168 for 80x86

What version is that in English? VC 6?
Can someone please tell me how to make my code work also with the old
headers.

Which old headers? The old headers are non-standard, and differ in
meaning depending upon the exact compiler you are using. I'll assume
you are using Microsoft's old headers.

In that case, you can't write code that works both for the old and new
headers, but here is some code that I suspect will work with the old
headers. Some old iostreams libraries had a class ostream_with_assign,
and if yours is one of them, this is what you need (untested since I
don't have any compilers that are old enough to compile it):

#include <iostream.h>
#include <fstream.h>

int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
ostream_with_assign oldcout = cout;
cout = file;
cout << "This is sent to file" << endl;
cout = oldcout;
cout << "This is also sent to prompt" << endl;
return 0;
}
Now you might ask why I don't just stick with the code that works.

Short explanation why it must work with the old headers:
I can't use the new headers (<iostream> and <fstream>).
I must use the old headers (<iostream.h> and <fstream.h>).

Longer explanation:
The reason why I can't use the new headers (which works in my example)
is that I use a program (ADS from Agilent) that generates all
C++-code. I only give a piece of code to ADS and it will include the
code in some function in a large and complex .cc-file which it will
then compile by automatic, and I can't change the headers it uses.

You should get them to fix it, since their code no longer works with
recent compilers.
Also, while I have been looking for a solution to my problem I came
across this piece of text that was found in the "basic_ios.h"-file
under my Cygwin-directory. I don't know if this is relevant for me,
but I strongly sense that it is related to my problem:

From "C:\cygwin\usr\include\c++\3.3.1\bits\basic_ios.h":
#########################################
/**
* @brief Accessing the underlying buffer.
* @return The current stream buffer.
*
* This does not change the state of the stream.
*/
basic_streambuf<_CharT, _Traits>*
rdbuf() const
{ return _M_streambuf; }

/**
* @brief Changing the underlying buffer.
* @param sb The new stream buffer.
* @return The previous stream buffer.
*
* Associates a new buffer with the current stream, and clears
the
* error state.
*
* Due to historical accidents which the LWG refuses to
correct, the
* I/O library suffers from a design error: this function is
hidden
* in derived classes by overrides of the zero-argument @c
rdbuf(),
* which is non-virtual for hysterical raisins. As a result,
you
* must use explicit qualifications to access this function via
any
* derived class.
*/
basic_streambuf<_CharT, _Traits>*
rdbuf(basic_streambuf<_CharT, _Traits>* __sb);
#########################################

I don't think that is relevant to your problem, but I may be wrong.
The above only applies to standard ostreams, and is the reason that:

std::eek:fstream ofs("Foo.txt");
ofs.rdbuf(std::cout.rdbuf());
doesn't work - you need:
std::eek:fstream ofs("Foo.txt");
ofs.std::eek:stream::rdbuf(std::cout.rdbuf());
or similar.

Tom
 
D

David Harmon

On 20 Jul 2004 07:26:10 -0700 in comp.lang.c++, (e-mail address removed)
(Omid) wrote,
Code that DOES NOT work:
##########################################
#include <iostream.h>
#include <fstream.h>

That covers it.
Use of <iostream.h> will lead to code that does not work.
 
R

rossum

Hi. [snip]

Code that works:
##########################################
#include <iostream>
#include <fstream>
using namespace std;
[snip]


Code that DOES NOT work:
##########################################
#include <iostream.h>
#include <fstream.h>

[snip]

It might be far too simple to work, but if you created a file called
iostream.h containing two lines:

- iostream.h ---------------
#include <iostream>
using namespace std;
----------------------------

it might just solve the problem. Keep a backup copy of the old
iostream.h file and put the two liner in the same directory. You
might also need to put a copy of iostream there as well.

Do the same for fstream.h

Might be worth a try.

rossum
 
O

Omid Rouhani

tom_usenet said:
On 20 Jul 2004 07:26:10 -0700, (e-mail address removed) (Omid) wrote:


What version is that in English? VC 6?

Yes, that's correct. It's VC 6.0.
I should have mentioned that.

Which old headers? The old headers are non-standard, and differ in
meaning depending upon the exact compiler you are using. I'll assume
you are using Microsoft's old headers.

In that case, you can't write code that works both for the old and new
headers, but here is some code that I suspect will work with the old
headers. Some old iostreams libraries had a class ostream_with_assign,
and if yours is one of them, this is what you need (untested since I
don't have any compilers that are old enough to compile it):

#include <iostream.h>
#include <fstream.h>

int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
ostream_with_assign oldcout = cout;
cout = file;
cout << "This is sent to file" << endl;
cout = oldcout;
cout << "This is also sent to prompt" << endl;
return 0;
}

Thanks a lot for your help. This was what I was looking for!
However, your "ostream_with_assign" should be changed to
"ostream_withassign", otherwise it's all correct and I'm able to
compile and link this file. So far everything is fine, but when I
execute the exe-file the program crashes and I get this error message:

The instruction at "0x00340905" referenced memory at "0x006811e8". The
memory could not be "written".
(The error is shown in the "standard Windows error window" with an ok
and cancel box.)

The program output:s "This is sent to prompt" and the test.txt is
created with the content "This is sent to file".
But the last message "This is also sent to prompt" isn't sent to
STDOUT.

Does anyone have any idea why this happens?
The compilation and linking is successful,
but during the execution I get this error.


I have also tried several modification of the code above.
One of them that is shown below can successfully be executed with
VC++,
but when I tried to compile exactly the same program with Cygwin g++,
it does not compile.
I'm only using standard headers now.
Why is it possible that it works with VC but not with G++?
Code:

//WORKS FINE WITH CL.EXE (VC++ 6.0)
//BUT NOT WITH CYGWIN G++
//################################
#include <iostream>
#include <fstream>

using namespace std;

class ostream_withassign : public ostream {
public:
ostream_withassign() : ostream((streambuf*)0) {}
~ostream_withassign() {}

ostream_withassign& operator=(ostream& __s) {
ios::init(__s.rdbuf());
return *this;
}
ostream_withassign& operator=(streambuf* __s) {
ios::init(__s);
return *this;
}
};

int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
ostream_withassign oldcout; //Split into 2 lines
oldcout= cout; //Split into 2 lines
cout = file;
cout << "This is sent to file" << endl;
cout = oldcout;
cout << "This is also sent to prompt" << endl;
return 0;
}
//################################


Note that I now use the standard header files (without .h).

Error using Cygwin g++ (3.3.1):
################
$ g++ mycout.cpp
/usr/include/c++/3.3.1/bits/ios_base.h: In member function `
std::basic_ios<char, std::char_traits<char> >& std::basic_ios<char,
std::char_traits<char> >::eek:perator=(const std::basic_ios<char,
std::char_traits<char> >&)':
/usr/include/c++/3.3.1/bits/ios_base.h:671: error: `std::ios_base&
std::ios_base::eek:perator=(const std::ios_base&)' is private
mycout.cpp:73: error: within this context
################





For a while I asked myself, is it possible that the problem
that the first program didn't work is in the .h-header files?
First I thought that made sense, but then I tried to compile
this program (using headers without ".h").


//WORKS WITH CYGWIN G++
//BUT NOT WITH CL.EXE (VC++) (compiles, but error when executed)
//################################
#include <iostream>
#include <sstream>
using namespace std;

int main ()
{

int val;
string mystr;
stringstream ss (stringstream::in | stringstream::eek:ut);

ss << "120 42 377 6 5 2000";
cout.rdbuf(ss.rdbuf());

for (int n=0; n<6; n++)
{
ss >> val;
cerr << val*2 << '\n';
}

cerr << "Hello World! " << '\n';

return 0;
}
//################################

This compiles and links without problem, and when executed all output
is sent to STDERR (also the last "Hello World" is outputted), but then
the program crashes with this error message:
The instruction at "0x00402f7f" referenced memory at "0x0000000sd".
The memory could not be "read".

The program does work fine Cygwin g++ (3.3.1)! But not with VC 6.0.
(compiled with "g++ test.cpp" and "cl /GX /TP test.cpp" (also compiled
with the entire development VC GUI, but with the same result)).

So now I don't know, is there a problem with my C++-code, or can my VC
be corrupt? Or is there some other explanation?



Once again, thanks to all of you helping me out with this!
Any help, ideas, clues or information is very much appreciated.

/Omid
 
T

tom_usenet

Thanks a lot for your help. This was what I was looking for!
However, your "ostream_with_assign" should be changed to
"ostream_withassign", otherwise it's all correct and I'm able to
compile and link this file. So far everything is fine, but when I
execute the exe-file the program crashes and I get this error message:

The instruction at "0x00340905" referenced memory at "0x006811e8". The
memory could not be "written".
(The error is shown in the "standard Windows error window" with an ok
and cancel box.)

Hmm, Microsoft still maintain documentation for this:
http://msdn.microsoft.com/library/d...clang98/HTML/_iostream_ostream_withassign.asp

It seems ostream_withassign doesn't have a correctly defined copy
constructor! So I think you need:

#include <iostream.h>
#include <fstream.h>

int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
ostream_with_assign oldcout;
oldcout = cout;
cout = file;
cout << "This is sent to file" << endl;
cout = oldcout;
cout << "This is also sent to prompt" << endl;
return 0;
}
The program output:s "This is sent to prompt" and the test.txt is
created with the content "This is sent to file".
But the last message "This is also sent to prompt" isn't sent to
STDOUT.

Does anyone have any idea why this happens?
The compilation and linking is successful,
but during the execution I get this error.

I think it's because the copy constructor doesn't do what I thought it
did, so you have to use default construction then assignment.
I have also tried several modification of the code above.
One of them that is shown below can successfully be executed with
VC++,
but when I tried to compile exactly the same program with Cygwin g++,
it does not compile.
I'm only using standard headers now.
Why is it possible that it works with VC but not with G++?

I think it might just be a fluke that it works with VC - the
assignment operator for ostream doesn't do anything useful, and what
you did was undefined behaviour that happened not to crash.
Code:

//WORKS FINE WITH CL.EXE (VC++ 6.0)
//BUT NOT WITH CYGWIN G++
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
ostream_withassign oldcout; //Split into 2 lines
oldcout= cout; //Split into 2 lines

Ahh, that's the same change I made above.
cout = file;

That there is the problematic line - cout doesn't have an assignment
operator. The code shouldn't compile at all, but there is a bug in
MSVC6's library that means it does.
cout << "This is sent to file" << endl;
cout = oldcout;
cout << "This is also sent to prompt" << endl;
return 0;
}
//################################


Note that I now use the standard header files (without .h).

Error using Cygwin g++ (3.3.1):
################
$ g++ mycout.cpp
/usr/include/c++/3.3.1/bits/ios_base.h: In member function `
std::basic_ios<char, std::char_traits<char> >& std::basic_ios<char,
std::char_traits<char> >::eek:perator=(const std::basic_ios<char,
std::char_traits<char> >&)':
/usr/include/c++/3.3.1/bits/ios_base.h:671: error: `std::ios_base&
std::ios_base::eek:perator=(const std::ios_base&)' is private
mycout.cpp:73: error: within this context

That error is exactly correct - ios_base::eek:perator= is private, and
therefore the code shouldn't compile. In MSVC6 it wasn't made private,
which is why it compiles successfully there.
//WORKS WITH CYGWIN G++
//BUT NOT WITH CL.EXE (VC++) (compiles, but error when executed)
//################################
#include <iostream>
#include <sstream>
using namespace std;

int main ()
{

int val;
string mystr;
stringstream ss (stringstream::in | stringstream::eek:ut);

ss << "120 42 377 6 5 2000";
cout.rdbuf(ss.rdbuf());

for (int n=0; n<6; n++)
{
ss >> val;
cerr << val*2 << '\n';
}

cerr << "Hello World! " << '\n';

Ahh, you're not resetting cout here, so it ends up containing a
dangling pointer to what was ss.rdbuf(). It then probably accesses
that during program shutdown, hence the error you mention below.
Once again, thanks to all of you helping me out with this!
Any help, ideas, clues or information is very much appreciated.

Someone else had the suggestion of forcing ADS to use the new headers
by usurping <iostream.h> with your own version that just includes
<iostream> and puts relevant names into namespace std.

Tom
 
O

Omid

tom_usenet said:
On 21 Jul 2004 11:32:22 -0700, minskrappost a_t hotmail.com (Omid Rouhani)
wrote:


Someone else had the suggestion of forcing ADS to use the new headers
by usurping <iostream.h> with your own version that just includes
<iostream> and puts relevant names into namespace std.

Tom

Yes, actually I tried to just replace the .h-files with my own header
files (that included <iostream> and used namespaces). However, it
didn't work since there were stuff in ADS that dependent on that the
old headers should be used and I got tons of errors.

However, I have solved my problems now.
My solution was to create a DLL-file with MinGW(.org) and call
functions in it from ADS.
That is, in my ADS code I just made a call for my own function that
was located in my DLL. Since I use MinGW to create my DLL I can use
any code I want (including using <iostream> and redirecing cout) in my
DLL.
The ADS still compiles using only the .h-files.

Hence, my problem is solved. I can now redirect cout anyway I want in
the DLL-file since it uses the <iostream>-header. No cout-redirection
is made in the code given to ADS.

Once again thanks to all of you taking time helping me out.

/Omid
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top