首页 > 解决方案 > 在win32中重定向标准输出不会重定向标准输出

问题描述

我正在尝试重定向标准输出,以便 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 似乎在做自己的事情。不幸的是,我需要重定向 printf,因为我正在尝试将 python 集成到 C++ 框架中,并且这似乎依赖于 printf 而不是 std::cout。

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

标签: c++cprintf

解决方案


由于缺乏适当的接口来映射任意 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);

这种重定向通常不会重定向由 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给 redirect 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. 使用 .将该新句柄分配给所需的 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);

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

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

推荐阅读