在Win32中重定向标准输出不会重定向标准输出

时间:2019-01-08 14:40:42

标签: c++ c printf

我正在尝试重定向标准输出,以便Windows应用程序中的printf可以转到我选择的文件。

我正在这样做:

outFile = fopen("log.txt", "w");
*stdout = *outFile;
setvbuf(stdout, NULL, _IONBF, 0);

但是printf仍会写入控制台(或在基于GUI的win32应用程序中无处显示)

我可以通过执行以下操作重定向“ std :: cout”:

outFileStr = std::ofstream(outFile);         
std::cout.rdbuf(outFileStr.rdbuf());

但是printf似乎正在做自己的事情。 不幸的是,当我试图将python集成到C ++框架中时,我需要重定向printf,这似乎依赖于printf而不是std :: cout。

std :: cout'似乎已重定向,但不是printf。

1 个答案:

答案 0 :(得分:5)

由于缺少在任意Win32文件句柄与高层文件描述符/流之间进行映射的适当接口,因此在Windows上重定向标准I / O的工作要多一些。

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

  1. 标准吗? C I / O流(printfscanf等使用...)
  2. POSIX I / O描述符(这些是readwrite,...使用的整数)
  3. Win32 API I / O句柄(由ReadFileWriteFile,...使用)

重定向C流

要重定向C流,可以使用freopen。例如,您可以使用以下命令重定向C stdout

freopen("log.txt", "w", stdout);

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

重定向POSIX I / O描述符

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

int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);

不幸的是,在Windows上,即使是POSIX API级别的重定向也不保证C或Win32 API级别的重定向。这是否有效取决于C库实现在POSIX文件描述符和Win32文件句柄之间进行映射所付出的努力(假定要使用的C运行时库将其I / O分层放置在POSIX之上) 。也不能保证此重定向将由产生的子代继承。

在Windows上重定向标准I / O!

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

  1. 通过调用CreateFile分配新的句柄。
  2. 使用SetStdHandle将新的句柄分配给所需的std I / O设备。
  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);

P.S。如果您可以在程序内部不进行I / O重定向,则可以使用一个小的Batch文件在命令行中简单地使用控制台的I / O重定向:

@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"