I've got a Windows Win32/GUI application that sometimes prints interesting output to both stdout
and stderr
, so what I'd like to do is capture that output into a file for review after the application has exited.
The problem is, I can successfully call freopen_s()
to capture stdout
output into a file, or I can use it to capture stderr
output into a file, but trying to do both at once yields only a truncated file with munged data.
Below is a simple program that reproduces the problem; if I comment out either one of the two freopen_s()
calls, then I get the expected output in the blah.txt
file that is created (i.e. one of the two text lines), but what I'd like is to end up with a blah.txt
containing both text lines.
Is that possible under Windows? I could fall back to creating two different files (e.g. blah_stdout.txt
and blah_stderr.txt
) but I'd rather not, since then I'd have to manually reconstruct the relative order in which stdout and stderr output was generated.
int main(int argc, char *argv[])
{
const char * outFileName = "blah.txt";
FILE * junk1 = NULL, junk2 = NULL;
if (freopen_s(&junk1, outFileName, "w", stdout) != 0) abort();
if (freopen_s(&junk2, outFileName , "w", stderr) != 0) abort();
printf("This text was printed to stdout and should appear in blah.txt\n");
fprintf(stderr, "This text was printed to stderr and should appear in blah.txt\n");
return 0;
}
The "w" open mode is documented as
Opens an empty file for writing. If the given file exists, its contents are destroyed.
but even "w+" and "a" fail.
If you are using a CRT that has dup2 you can do this:
#include <io.h> // MS CRT
...
FILE * junk1 = NULL;
if (freopen_s(&junk1, outFileName, "w", stdout) != 0) abort();
_dup2(1, 2); // Assign stderr to same file as stdout
This code wrote both lines to the file when I tested it but it is evident from the comments that this might not always be the case. Older versions of Visual Studio are more likely to work.
If you are willing to throw out all portability you might also be able to access the struct behind the FILE objects (struct _iobuf
) directly (_iob
/__iob_func
) and overwrite the members with the values from the other FILE. This is not possible in VS 2015 and later:
FILE Encapsulation: In previous versions, the FILE type was completely defined in <stdio.h>, so it was possible for user code to reach into a FILE and muck with its internals. We have refactored the stdio library to improve encapsulation of the library implementation details. As part of this, FILE as defined in is now an opaque type and its members are inaccessible from outside of the CRT itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With