【问题标题】:why close() system call flushing the output?为什么 close() 系统调用刷新输出?
【发布时间】:2011-12-06 06:35:53
【问题描述】:

这是我的代码:

#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
int main(int argc,char *argv[])
{
  int oldfd;
  int newfd;
  if(argc!=2)
  {
    printf("Usgae : %s file_name\n",argv[0]);
    exit(0);
  }
 oldfd=open(argv[1],O_RDWR|O_APPEND,S_IRWXU); // Opening the file in Read/Write mode
 if (-1 == oldfd)
 {
  perror("Error opening file");
  exit(0);
 }
 close(1); // closing stdout 
 newfd=dup(oldfd); //Now this newfd holds the value 1 
 close(oldfd); //closing the oldfd
 printf("\nStack Overflow"); //Now this printf will print content into the file as stdout closed already
 close(newfd);// closing newfd 
 return 0;
}

我实际上想要做的只是使用 printf() 而不是 write() 系统调用将“堆栈溢出”打印到文件中。

它没有将内容打印到文件中。但我观察到的一件事是,如果我删除代码:

 close(newfd)

它按预期将内容打印到文件中。但我不明白为什么。我打印了内容,然后才关闭 newfd。

这是什么原因?

【问题讨论】:

  • 例如,为了不经常写入磁盘。效率。
  • 你为什么不直接使用fprintf(fd, fmt, ...)?我不确定尝试重用 fd=1 是否是一个好主意,甚至是否已定义。
  • jedwards,我实际上是想知道为什么这不起作用:)

标签: c unix dup


【解决方案1】:

这里实际发生的是printf 的输出被缓冲而不是立即发送到 fd 1;相反,在您从main 返回后,C 运行时会将缓冲区刷新到文件描述符 1。如果您close(newfd),则您实际上阻碍了退出时运行时执行的自动刷新。

如果您在close(newfd) 之前明确fflush(stdout),则您的输出应该出现在文件中。

顺便说一句,如果你想重定向一个特定的文件描述符,有一个备用系统调用dup2(oldfd, 1),它使 fd 1 成为 oldfd 的副本,如果 fd 1 之前打开,则关闭它。

【讨论】:

    【解决方案2】:

    当您直接使用文件描述符时,您将希望避免使用诸如printf 之类的C stdio 函数。从 stdio 层下更改底层文件描述符似乎充满危险。

    如果您将printf 更改为以下内容:

    write(newfd, "\nStack Overflow", 15);
    

    那么您可能会得到您期望的输出(无论您的close(newfd) 与否)。

    【讨论】:

      【解决方案3】:

      closewriteopensystem calls 主要在linux kernel 内完成;所以从应用的角度来看,它们是基本的原子操作。

      printffprintf 是构建在这些(和其他)系统调用之上的标准库函数。

      exit-ing之前(例如从main返回),标准库和环境(特别是crt*.o中的代码调用你的main)正在执行atexit注册的函数;并且标准 I/O 是(某种程度上)在退出时注册对 fflush 的调用。所以stdout 在退出时是fflush-ed。如果您在 main 中 close 它的描述符,则刷新失败并且什么也不做。

      我认为您不应该将stdio 和原始write-s 混合到同一个写入描述符中。考虑使用fdopen or freopen

      【讨论】:

        猜你喜欢
        • 2019-11-22
        • 1970-01-01
        • 1970-01-01
        • 2014-09-28
        • 2018-11-10
        • 2022-10-02
        • 1970-01-01
        • 1970-01-01
        • 2015-10-05
        相关资源
        最近更新 更多