在Windows上重定向标准输出和标准错误

3

我有一个Windows GUI应用程序,使用第三方库将调试/错误信息输出到stdout/stderr。我发现了许多重定向它们到我的日志文件的解决方案,但只有 1.5 / 4 可以按照预期工作。我在WinXP SP3 32位上使用VS 2008 SP1。我没有包含错误处理,但是没有任何调用返回错误。

// First one:
SetStdHandle(STD_OUTPUT_HANDLE, (HANDLE)_get_osfhandle(_fileno(log_file.get_FILE())));
SetStdHandle(STD_ERROR_HANDLE, (HANDLE)_get_osfhandle(_fileno(log_file.get_FILE())));

printf("%s", "1 Test printf to cout!\n");
fprintf(stderr, "%s", "1 Test printf to cerr!\n");

std::cout << "1 Test print to cout!\n";
std::cerr << "1 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);


// Second one:
_dup2(_fileno(log_file.get_FILE()), _fileno(stdout));
_dup2(_fileno(log_file.get_FILE()), _fileno(stderr));

printf("%s", "2 Test printf to cout!\n");
fprintf(stderr, "%s", "2 Test printf to cerr!\n");

std::cout << "2 Test print to cout!\n";
std::cerr << "2 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);


// Third one:
std::ofstream out_stream(log_file.get_FILE());
std::cout.rdbuf(out_stream.rdbuf());
std::cerr.rdbuf(out_stream.rdbuf());

printf("%s", "3 Test printf to cout!\n");
fprintf(stderr, "%s", "3 Test printf to cerr!\n");

std::cout << "3 Test print to cout!\n";
std::cerr << "3 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);


// Fourth one:
*stdout = *log_file.get_FILE();
*stderr = *log_file.get_FILE();

printf("%s", "4 Test printf to cout!\n");
fprintf(stderr, "%s", "4 Test printf to cerr!\n");

std::cout << "4 Test print to cout!\n";
std::cerr << "4 Test print to cerr!\n";

fflush(stdout);
fflush(stderr);

在我进行测试后(当然是分别测试),我得到了以下结果:
3 将输出打印到cout!
3 将输出打印到cerr!
4 将printf输出到cout!
4 将输出打印到cout!
4 将printf输出到cerr!
4 将输出打印到cerr!

为什么只有最后一个解决方案能完全工作?使用它是否安全?

更新。XCode测试结果:
2 将printf输出到cout!
2 将输出打印到cout!
2 将printf输出到cerr!
2 将输出打印到cerr!
4 将printf输出到cout!
4 将输出打印到cout!
4 将printf输出到cerr!
4 将输出打印到cerr!
第一个显然只适用于Windows,第三个因为没有接受FILE*参数的文件流构造函数而失败。


1
我怀疑:第一个设置标准输出/错误句柄,在标准库已经使用旧的句柄来设置stdout/stderr之后。第二个可能不起作用,因为Windows不使用文件描述符。第三个仅适用于cout/cerr,因为您实际上没有对stdout/stderr进行任何操作。最后一个是丑陋的非可移植性的hack。 - user253751
@immibis,解决方案是什么?我马上会在OSX上测试其中的3个。 - Sergi0
1
@immibis 为什么你称最后一个为丑陋的不可移植的黑客?丑陋是一种观点,我更关心的是不可移植的部分。 - Avi Ginsburg
这些都不会重定向标准输出和标准错误。 - Shark
1
@Shark 第四个是标准输出和标准错误的重定向。如果不保存原始指针,原始指针就永远不会被关闭或恢复(无耻的插入),但它们会被重定向。 - Avi Ginsburg
显示剩余23条评论
1个回答

0

从结尾开始:

  1. 你正在更改实际的 FILE 指针,使其指向标准输出和标准错误。很明显为什么它能工作。std::cout 和 std::cerr 最终将输出发送到这些指针。

  1. std::ios.rdbuf 可以改变 std::ios 实例(在这个例子中是 std::cout 和 std::cerr)发送其流的

  1. 我从未听说过这个。可能需要进行一些研究并编辑答案。

  1. 和2一样。

Markdown将您的数字重新格式化为4/5/6/7,而不是4/3/2/1。 - user253751
我猜你的意思是4-3-2-1 :) 好吧,我查了一下stdout的定义,它看起来像这样#define stdout (&__iob_func()[1]),所以我不确定第四个解决方案有多安全。 - Sergi0
@Sergi0 这只是一个包含描述符(FILE指针)的数组。 - Avi Ginsburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接