Jump to content
  • Advertisement
MarcusAseth

Win32 application| cout output both on console and on file

This topic is 428 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone, the code below is my setup for opening a console in a Win32 project (using visual studio) and having the cout print stuff on it, it is mostly copy-pasted from stackoverflow with  some trial and error changes I did without being sure of what I was doing, but it works. Though now I want to understand it, code below

void debugConsole(bool create = true);

int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int show)
{
#if defined(DEBUG) || defined(_DEBUG)
	debugConsole();
#endif

	return 0;
}

void debugConsole(bool create)
{
	if (create)
	{
	//Create Console
	FILE* stream;
	AllocConsole();
	freopen_s(&stream, "conout$", "w", stdout);
	}
}

 

So from what I can tell, I am telling it that now the stdout stream (stuff I send using std::cout) get written (that's why the "w") to the console output, which is specified using "conout$".

So basically freopen_s job is to send a stream somewhere else?

But where is the "conout$" coming from? There is like a switch inside freopen_s that tells it the meaning of "conout$", which would be "send stuff to console"?

What is the FILE* stream sent to freopen_s doing though?

also let's say that under that line I write

freopen_s(&stream, "output.txt", "w", stdout);

I tried this out and it creates said file and put the cout output into it, which is great, but what if I want both? How do I set it up in a way than now cout content is cloned and sent both to the console and to my output file? 

Thanks :)

Edited by MarcusAseth

Share this post


Link to post
Share on other sites
Advertisement
52 minutes ago, MarcusAseth said:

So basically freopen_s job is to send a stream somewhere else?

The documentation is here.  It closes the file pointer and re-assigns the stream, you can read more at the link.

52 minutes ago, MarcusAseth said:

But where is the "conout$" coming from? There is like a switch inside freopen_s that tells it the meaning of "conout$", which would be "send stuff to console"?

Close.  It is not handled inside that function, but it is handled by the system.

It is one of several special file names that Windows recognizes.  There are a bunch of them for things like console input/output, serial port input/output, and various other special devices and special features.  There are similar special device names on other operating systems like Linux or OSX or other systems. 

Both CONIN$ and CONOUT$ are managed by Windows so you don't have to.  Assuming they exist and haven't already been redirected in your program, that can work as you describe, sending stuff to the console.

52 minutes ago, MarcusAseth said:

I tried this out and it creates said file and put the cout output into it, which is great, but what if I want both? How do I set it up in a way than now cout content is cloned and sent both to the console and to my output file? 

The cout object is nothing particularly fancy, it is an output stream that happens to point to a specific location.  You have an output file that is also an output stream pointing to a different specific location.

If you want to write to them both, then do it:

cout << stuffToWrite;
myfile << stuffToWrite;

Share this post


Link to post
Share on other sites

I see.

This gives me an idea, can I create my personal stream object that overload the operator<< so that when I call

MySuperCout << "important stuff" << endl;

it sends the content both to cout and to myfile as in your example above.

Seems reasonable, I go to try it out, thanks! :D

Share this post


Link to post
Share on other sites

I've encountered some obstacles :S

I was thinking something like the code below should do the trick

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

class MyCout {
public:
	MyCout(string filename) :mFilename{filename} {}
	MyCout& operator<<(const string s)
	{
		mMyFile.open(mFilename, ofstream::out);
		
		cout << s; 
		mMyFile << s;
		
		mMyFile.close();
		return *this;
	}
private:
	ofstream mMyFile;
	string mFilename;
};


int main()
{
	MyCout stream1("outputFile1.txt");
	stream1 << "test_test_test" << endl;

}

 

But it only works with string since I've overloaded the operator<< only for that, therefore endl don't work with it (unleass I overload for that as well).

There is a more clever way to do this, like inheriting from something similar to cout to have my own stream class while getting all the operator<< overload behaviours of the cout? :P

 

What would really solve my problem is something like this

MyCout& operator<<(WatheverType& t)
{
	cout << t;
}

the ability of having my operator<< accept every type because inside, cout and the fstream are going to handle wathever anyway.

There is any wizardry I can do with templates or something to achieve that? :S

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

Yes you could write something like

template <typename T> void Log(const T &t)
{
  std::cout << t;
}

that will work as expected for the reason of compile time resolve of T.

What I've did a long time ago was redirecting the standard output and error channels to achive something like you would like to using the rdbuf properties

std::ofstream out("log.txt");
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
std::cout.rdbuf(out.rdbuf()); //redirect std::cout to file

//do all the logging between here

std::cout.rdbuf(coutbuf); //reset to standard output

using an own implementation of a buffer object that was intended to do tripple; output to file, output to game console, output to debug console whenever buffer was filled.

class logbuf : public std::streambuf 
	{
		private:
			char buffer[STREAMBUFFER_SIZE];

			int overflow(int c) 
			{
				if (!std::streambuf::traits_type::eq_int_type(c, std::streambuf::traits_type::eof())) 
				{
					*this->pptr() = std::streambuf::traits_type::to_char_type(c);
					this->pbump(1);
				}
				return this->sync()? std::streambuf::traits_type::not_eof(c): std::streambuf::traits_type::eof();
			}

			int sync() 
			{
				if (this->pbase() != this->pptr())
				{
					if(callback)
						this->callback(std::string(this->pbase(), this->pptr()));
					this->setp(this->pbase(), this->epptr());
				}
				return 0;
			}

		public:
			delegate<void (std::string)> callback;

			logbuf()
			{
				memset(buffer,0,sizeof(buffer));
				this->setp(this->buffer, this->buffer + sizeof(this->buffer) - 1);
			}
	};
      

 

Here a delegate was called whenever something was pushed into the buffer where the delegate could be bound to anything that accepts std::string as parameter and has no return type.

This code is higly obsolete so should not be used but you could get a view of how your goal could be achieved. Meanwhile I use a different approach away from the STL simply similar to C#'s string.Format function as a thread-safe templated argument to text conversion function.

#define __log(...) Log::Write(Log::Message, __VA_ARGS__)
#define __err(...) Log::Write(Log::Error, __VA_ARGS__)
...
  
__log("{0} Cores Found", GetSystemCores()); //results in '16 Cores Found'

 

Share this post


Link to post
Share on other sites

Thank you for the examples Shaarigan, though actually the template example doesn't quite fit my needs because I want the ability to concatenate a series of operator<< as when you normally do a cout.

 

I went with this (code below), I've overloaded operator<< on a sstream adding my class, so when I pass it it flushes the stringstream both into cout and into my file. I can both concatenate and write a single line, seems a reasonable way to do it, right? :P

#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;

struct MyCout {
	MyCout(string filename) { myFile.open(filename, ofstream::out); }
	inline stringstream& print() {
                                        string s; stream >> s;
                                        cout << s; myFile << s;
                                        return stream;
	}
	stringstream stream;
	ofstream myFile;
};
ostream& operator<<(ostream& stream, MyCout& debug) { return debug.print(); }
  
  int main()
  {
  	MyCout debug("outputFile1.txt");
	debug.stream << "test_test_test" << endl << debug;
  
  	return 0;
  }

 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

In operator case, macro definitions could be your friend ;) but your solution seems fair enougth when working for your needs :D

#define InputOperator(type) std::ostream& operator<<(type const& tp) \
{  \
    std::cout << tp; \
    myFile << tp; \
    return *this;  \
}

InputOperator(unsigned char)
InputOperator(signed char)
InputOperator(unsigned short)
InputOperator(signed short)
InputOperator(unsigned int)
InputOperator(signed int)
InputOperator(unsigned long)
InputOperator(signed long)
InputOperator(float)
InputOperator(double)
InputOperator(const char*)
InputOperator(std::string)

 

Edited by Shaarigan

Share this post


Link to post
Share on other sites

lol it won't compile :P

 

Edit: apologize, it works, it was missing some '\' because maybe I messed up while pasting, but learned a new thing, thanks a lot! :D

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!