3

我有一个 Windows Win32/GUI 应用程序,它有时会向stdout和打印有趣的输出stderr,所以我想做的是在应用程序退出后将该输出捕获到一个文件中以供查看。

问题是,我可以成功调用freopen_s()以将输出捕获stdout到文件中,或者我可以使用它来将stderr输出捕获到文件中,但是尝试同时执行这两种操作只会产生一个带有经过处理的数据的截断文件。

下面是一个重现问题的简单程序;如果我注释掉这两个freopen_s()调用中的任何一个,那么我会在blah.txt创建的文件中得到预期的输出(即两个文本行之一),但我想要的是最终blah.txt包含两个文本行。

在Windows下可以吗?我可以回退到创建两个不同的文件(例如blah_stdout.txtblah_stderr.txt),但我宁愿不这样做,因为那时我必须手动重建生成 std​​out 和 stderr 输出的相对顺序。

int main(int argc, char *argv[])
{
   const char * outFileName = "blah.txt";
   FILE * junk1 = NULL, junk2 = NULL;
   if (freopen_s(&junk1, outFileName, "w", stdout) != 0) abort();
   if (freopen_s(&junk2, outFileName , "w", stderr) != 0) abort();
   printf("This text was printed to stdout and should appear in blah.txt\n");
   fprintf(stderr, "This text was printed to stderr and should appear in blah.txt\n");
   return 0;
}
4

1 回答 1

2

“w”打开模式记录为

打开一个空文件进行写入。如果给定文件存在,则其内容将被销毁。

但即使是“w+”和“a”也失败了。

如果您使用的是具有 dup2 的 CRT,您可以这样做:

#include <io.h> // MS CRT

...

FILE * junk1 = NULL;
if (freopen_s(&junk1, outFileName, "w", stdout) != 0) abort();
_dup2(1, 2); // Assign stderr to same file as stdout

这段代码在我测试时将两行都写入了文件,但从注释中可以明显看出,情况并非总是如此。较旧版本的 Visual Studio 更有可能工作。

如果您愿意放弃所有可移植性,您也可以直接访问 FILE 对象 ( struct _iobuf) 后面的结构 ( _iob/ __iob_func) 并用其他 FILE 中的值覆盖成员。这在 VS 2015 及更高版本中是不可能的

FILE 封装:在以前的版本中,FILE 类型完全在 <stdio.h> 中定义,因此用户代码可以访问 FILE 并破坏其内部。我们重构了 stdio 库以改进对库实现细节的封装。作为其中的一部分,定义的 FILE 现在是不透明类型,并且无法从 CRT 本身外部访问其成员。

于 2018-05-15T19:51:48.210 回答