为什么close()系统调用刷新输出?

时间:2011-12-06 06:35:54

标签: c unix dup

这是我的代码:

#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()系统调用将“Stack Overflow”打印到文件中。

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

 close(newfd)

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

是什么原因?

3 个答案:

答案 0 :(得分:5)

这里实际发生的是printf的输出被缓冲而不立即发送到fd 1;而是从main返回后,C运行时将缓冲区刷新到文件描述符1。如果你close(newfd),你已经有效地阻止了退出时运行时执行的自动刷新。

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

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

答案 1 :(得分:0)

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

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

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

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

答案 2 :(得分:0)

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

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

exit之前(例如从main返回),标准库和环境(特别是调用crt*.o的{​​{1}}中的代码)正在执行这些功能由atexit注册;并且标准I / O是(排序)在退出时注册对fflush的调用。因此main在退出时是stdout。如果你在main中fflush它的描述符,则刷新失败并且什么都不做。

我认为你不应该将close和raw stdio - s混合到同一个写描述符中。考虑使用fdopen or freopen