我正在尝试重定向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.
由于缺少适当的接口来映射任意Win32文件句柄和更高层文件描述符/流,因此重定向标准I/O在Windows上更为复杂.
Windows上实际上有三层不同的I/O:
printf,scanf...)read,write,...)ReadFile,WriteFile,...)要重定向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 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上正确重定向I/O,您必须在最低级别(即Win32 API级别)重定向并在更高级别修复链接,如下所示:
CreateFile.SetStdHandle._open_osfhandle(返回文件描述符编号)将新句柄与相应的C std文件描述符相关联.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)