问题
I'm trying to redirect stdout so that printf in a windows application will go to a file of my choice.
I'm doing this:
outFile = fopen("log.txt", "w");
*stdout = *outFile;
setvbuf(stdout, NULL, _IONBF, 0);
but printf still writes to the console (or nowhere on a GUI based win32 application)
I can redirect 'std::cout' by doing this:
outFileStr = std::ofstream(outFile);
std::cout.rdbuf(outFileStr.rdbuf());
But printf seems to be doing its own thing. Unfortunately, I need to redirect printf as I'm trying to integrate python in to a C++ framework and that appears to rely on printf rather than std::cout.
std::cout' seems to be redirected but not printf.
回答1:
Redirecting standard I/O is a bit more involved on Windows due to the lack of a proper interface to map between arbitrary Win32 file handles and higher layer file descriptors/streams.
There are actually three different layers of I/O on Windows:
- Standard? C I/O streams (these are used by
printf
,scanf
, ...) - POSIX I/O descriptors (these are integers used by
read
,write
, ...) - Win32 API I/O handles (used by
ReadFile
,WriteFile
, ...)
Redirecting C Streams
To redirect C streams you can use freopen. For instance, you can redirect C stdout
using:
freopen("log.txt", "w", stdout);
This redirection will generally not redirect I/O done by POSIX or Win32 APIs (they would still read/write the attached Console, if any). In addition, this redirection will not be inherited by child processes. (On POSIX-compliant/non-Windows systems, it is typical that the POSIX API is also the system API and the C API is implemented on top of the POSIX API. In these cases, freopen
is sufficient.)
Redirecting POSIX I/O descriptors
To redirect I/O at the POSIX API level, you can use dup2. For example, you can reassign file descriptor STDOUT_FILENO
to redirect stdout
, something like:
int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);
Unfortunately on Windows, even redirection at the POSIX API level does not guarantee redirection neither at the C nor the Win32 API levels. Whether this will work or not depends on the effort put in the implementation of the C library to map between POSIX file descriptors and Win32 file handles (presuming the C runtime library you are using layered its I/O on top of POSIX to begin with). There is also no guarantee that this redirection will be inherited by spawned children.
Redirecting Std I/O On Windows!
To correctly redirect I/O on Windows you have to redirect at the lowest level (i.e., the Win32 API level) and fix the linkage at higher levels as follows:
- Allocate a new handle by calling CreateFile.
- Assign that new handle to the desired std I/O device using SetStdHandle.
- Associate that new handle with the corresponding C std file descriptor using _open_osfhandle (returns a file descriptor number).
- Redirect the returned file descriptor using the
dup2
technique explained above.
Here is a sample snippet to redirect stdout
:
HANDLE new_stdout = CreateFileA("log.txt", ...);
SetStdHandle(STD_OUTPUT_HANDLE, new_stdout);
int fd = _open_osfhandle(new_stdout, O_WRONLY|O_TEXT);
dup2(fd, STDOUT_FILENO);
close(fd);
P.S. If you can do without I/O redirection inside the program, then you can simply use the Console's I/O redirection at the command line using a tiny Batch file:
@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"
来源:https://stackoverflow.com/questions/54094127/redirecting-stdout-in-win32-does-not-redirect-stdout