Redirecting stdout/stderr on Windows

2.4k views Asked by At

I have a Windows GUI app that uses third-party libraries that print debug/error information to stdout/stderr. I have found numerous solutions for redirecting them to my log file. But only 1.5 out of 4 work as expected. I am using VS 2008 SP1 on WinXP SP3 32-bit. I didn't include error handling, but no calls return errors.

// First one:
SetStdHandle(STD_OUTPUT_HANDLE, (HANDLE)_get_osfhandle(_fileno(log_file.get_FILE())));
SetStdHandle(STD_ERROR_HANDLE, (HANDLE)_get_osfhandle(_fileno(log_file.get_FILE())));

printf("%s", "1 Test printf to cout!\n");
fprintf(stderr, "%s", "1 Test printf to cerr!\n");

std::cout << "1 Test print to cout!\n";
std::cerr << "1 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);


// Second one:
_dup2(_fileno(log_file.get_FILE()), _fileno(stdout));
_dup2(_fileno(log_file.get_FILE()), _fileno(stderr));

printf("%s", "2 Test printf to cout!\n");
fprintf(stderr, "%s", "2 Test printf to cerr!\n");

std::cout << "2 Test print to cout!\n";
std::cerr << "2 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);


// Third one:
std::ofstream out_stream(log_file.get_FILE());
std::cout.rdbuf(out_stream.rdbuf());
std::cerr.rdbuf(out_stream.rdbuf());

printf("%s", "3 Test printf to cout!\n");
fprintf(stderr, "%s", "3 Test printf to cerr!\n");

std::cout << "3 Test print to cout!\n";
std::cerr << "3 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);


// Fourth one:
*stdout = *log_file.get_FILE();
*stderr = *log_file.get_FILE();

printf("%s", "4 Test printf to cout!\n");
fprintf(stderr, "%s", "4 Test printf to cerr!\n");

std::cout << "4 Test print to cout!\n";
std::cerr << "4 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);

After I tested them (separately, of course), I got these results:
3 Test print to cout!
3 Test print to cerr!
4 Test printf to cout!
4 Test print to cout!
4 Test printf to cerr!
4 Test print to cerr!

Why does only the last solution work fully? Is it safe to use it?

Update. XCode test results:
2 Test printf to cout!
2 Test print to cout!
2 Test printf to cerr!
2 Test print to cerr!
4 Test printf to cout!
4 Test print to cout!
4 Test printf to cerr!
4 Test print to cerr!
First one is obviously Windows only, and the third one fails cause there is no file stream constructor that takes FILE* parameter.

1

There are 1 answers

3
Avi Ginsburg On

From the end:

  1. You're changing the actual FILE pointer to stdout and stderr. Obvious why it works. std::cout and std::cerr eventually send output to these pointers.

  1. std::ios.rdbuf changes the stream where the instance of std::ios (in this case std::cout and std::cerr) send it's stream.

  1. I never heard of it. I may do a bit of research and edit the answer.

  1. Same as 2.