在win32中重定向stdout不会重定向stdout

Lut*_*her 1 c c++ printf

我正在尝试重定向stdout,以便Windows应用程序中的printf将转到我选择的文件.

我这样做:

outFile = fopen("log.txt", "w");
*stdout = *outFile;
setvbuf(stdout, NULL, _IONBF, 0);
Run Code Online (Sandbox Code Playgroud)

但printf仍然写入控制台(或基于GUI的win32应用程序无处可写)

我可以通过这样做重定向'std :: cout':

outFileStr = std::ofstream(outFile);         
std::cout.rdbuf(outFileStr.rdbuf());
Run Code Online (Sandbox Code Playgroud)

但是printf似乎在做自己的事情.不幸的是,我需要重定向printf,因为我正在尝试将python集成到C++框架中,并且它似乎依赖于printf而不是std :: cout.

std :: cout'似乎被重定向但不是printf.

Joh*_*ohn 5

由于缺少适当的接口来映射任意Win32文件句柄和更高层文件描述符/流,因此重定向标准I/O在Windows上更为复杂.

Windows上实际上有三层不同的I/O:

  1. 标准?CI/O流(这些被使用的printf,scanf...)
  2. POSIX I/O描述符(这些都是使用整数read,write,...)
  3. Win32 API的I/O句柄(通过使用ReadFile,WriteFile,...)

重定向C流

要重定向C流,您可以使用freopen.例如,您可以stdout使用以下方法重定向C :

freopen("log.txt", "w", stdout);
Run Code Online (Sandbox Code Playgroud)

此重定向通常不会重定向POSIX或Win32 API完成的I/O(如果有的话,它们仍会读取/写入连接的控制台).此外,子进程不会继承此重定向.(在POSIX兼容/非Windows系统上,通常POSIX API也是系统API,而C API是在POSIX API之上实现的.在这些情况下,freopen就足够了.)

重定向POSIX I/O描述符

要在POSIX API级别重定向I/O,您可以使用dup2.例如,您可以重新分配文件描述符STDOUT_FILENO以重定向stdout,例如:

int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);
Run Code Online (Sandbox Code Playgroud)

不幸的是,在Windows上,即使在POSIX API级别进行重定向也不能保证在C和Win32 API级别都不进行重定向.这会不会起作用与否取决于放在C库以POSIX文件描述符和Win32文件句柄之间进行映射的执行工作(假设你正在使用POSIX的顶部分层的I/O开始与C运行时库) .也不能保证这个重定向将由衍生的子项继承.

在Windows上重定向Std I/O!

要在Windows上正确重定向I/O,您必须在最低级别(即Win32 API级别)重定向并在更高级别修复链接,如下所示:

  1. 通过调用分配新句柄CreateFile.
  2. 使用将新句柄分配给所需的std I/O设备SetStdHandle.
  3. 使用_open_osfhandle(返回文件描述符编号)将新句柄与相应的C std文件描述符相关联.
  4. 使用上述dup2技术重定向返回的文件描述符.

以下是要重定向的示例代码段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);
Run Code Online (Sandbox Code Playgroud)

PS如果您无法在程序内部进行I/O重定向,那么您可以使用一个很小的批处理文件在命令行中使用控制台的I/O重定向:

@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"
Run Code Online (Sandbox Code Playgroud)