标准输出重定向无法工作,如果标准输出是一个文件。

5

在调用一个写于Fortran的外部库中的嘈杂函数之前,我使用以下代码来重定向标准输出:

// copy standard output
out = dup(STDOUT_FILENO);

// close standard output
close(STDOUT_FILENO);

// use log file as standard output
log = open(log_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if(log != STDOUT_FILENO)
    fprintf(stderr, "could not create log file %s", log_file);

// call the library function that uses a lot of printf
func();

// restore original standard output
dup2(out, STDOUT_FILENO);

// close copy of standard output
close(out);

总结以上代码片段的意图:复制标准输出,关闭标准输出(释放文件描述符0),打开文件(使用最低的文件描述符=0=stdout),使用重定向的标准输出运行代码,并重置标准输出。
当我在终端上使用标准输出时,这个方法能完美地运行我的代码。然而,当我将标准输出设置为一个文件(使用$ mycode > myfile.txt命令)时,重定向失败了,导致我在myfile.txt中看到的是func()函数的输出,而不是日志文件的输出。这是怎么回事呢?

我已将其简化为最小测试用例,问题未出现。这让我相信它可能是Fortran/C交互的产物。Fortran是否有可能以某种方式缓冲输出,并在重置后写入stdout?但是,为什么它不会与C的随后输出混合在一起呢? - user4267489
1
如果Fortran正在缓冲输出,那么它有可能使用与C的fwrite()相同的缓冲区。另外,C运行时或您的辅助库在您的C代码尝试写入stdout时也有可能刷新Fortran的缓冲区。 - Kevin
1
在恢复原始的stdout之前,你可以尝试使用fflush(stdout)吗? - JS1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - fuz
@njt 根据 POSIX,STDOUT_FILENO 等于 1。你的程序可能在关闭标准输入的情况下运行。 - fuz
显示剩余5条评论
1个回答

6

在使用dup2恢复原始的stdout之前,您需要执行fflush(stdout)

这样做的原因是终端的stdout是行缓冲的。因此,您的输出会立即刷新到重定向文件中。但是,当您将stdout设置为文件时,stdout变为完全缓冲,因此您的func输出将被缓冲等待刷新。当您恢复原始的stdout而不刷新时,输出将在程序退出时写入原始的stdout。


感谢您对stdout缓冲区的解释,这解释了观察到的行为。我已经尝试过fflush(stdout)fflush(log)(在使用fopen()打开日志文件后)。我还将尝试调用Fortran的 FLUSH,如果可能的话。 - user4267489
在我的代码末尾使用简单的fprintf(stderr, "waiting\n"); fflush(stderr); sleep(1000);,我发现实际上直到程序退出才会有任何输出被写入。因此,当Fortran输出从缓冲区刷新时,stdout早已被重置为其原始状态。我将把这个答案标记为被接受的,因为它解释了观察到的行为。 - user4267489
我发现的一个解决方法是:问题在于,程序结束时Fortran缓冲区中剩余的内容将被写入原始的stdout。因此,在终止之前,我现在重新定向回日志文件,以便重定向输出的最后部分也写入那里。 - user4267489

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