C 如果stdout是文件,则stdout重定向不起作用

C 如果stdout是文件,则stdout重定向不起作用,c,posix,stdout,io-redirection,C,Posix,Stdout,Io Redirection,在从用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 != STDO

在从用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);
为了总结我对上述代码片段的意图:复制stdout、关闭stdout(释放文件描述符0)、打开文件(使用最低文件描述符=0=stdout)、使用重定向的stdout运行代码,以及重置stdout


当我使用终端作为标准输出运行我的代码时,这非常有效。但是,当我将stdout设置为一个文件(使用
$mycode>myfile.txt
)时,重定向失败,结果是在
myfile.txt
中输出
func()
,而不是日志文件。这是怎么可能的?

在使用
dup2
还原原始stdout之前,需要执行
fflush(stdout)


它与终端一起工作的原因是,stdout是终端的行缓冲。因此,您的输出会立即刷新到重定向文件。但是,当您用stdout启动程序时,stdout将被完全缓冲,因此
func
输出将在缓冲区中等待刷新。当您在不刷新的情况下恢复原始标准输出时,当程序退出时,输出将写入原始标准输出。

我已将其简化为最小测试用例,并且问题不会出现。这让我相信这可能是Fortran/C交互的产物。Fortran是否可能以某种方式缓冲输出,并在重置后将其写入标准输出?但是,为什么它不会与C的后续输出混淆呢?如果Fortran正在缓冲输出,那么它可能使用与C的
fwrite()
相同的缓冲区。当C代码试图写入标准输出时,也可能是C运行时或帮助程序库正在刷新Fortran的缓冲区。在还原原始标准输出之前,是否可以尝试
fflush(标准输出)
?您可能需要使用
dup2()
要将日志文件中的文件描述符放在正确的位置,因为不能保证该文件最终会得到文件描述符
标准输出文件号
@fuzzxl
打开的定义是“打开()函数应返回指定文件的文件描述符,该文件描述符是当前未为该进程打开的最低文件描述符。“由于0最近被释放,因此它将为0。感谢您对stdout缓冲的解释,这解释了观察到的行为。我现在尝试了
fflush(stdout)
fflush(log)
(在使用
fopen()打开日志文件后)但未成功。如果可能的话,我还会尝试调用Fortran的
FLUSH
;fflush(stderr);睡眠(1000)在我的代码结束时,我可以看到,事实上,在程序退出之前,不会写入任何内容。因此,当Fortran输出从缓冲区刷新时,stdout早已重置为其原始状态。我将此标记为可接受的答案,因为它解释了观察到的行为。我发现产生预期结果的一个解决方法是:问题是,程序结束时Fortran缓冲区中剩余的内容将写入原始标准输出。因此,在终止之前,我现在重定向回日志文件,以便重定向输出的最后一部分也写入其中。