3

这是我的代码:

#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。

这是什么原因?

4

3 回答 3

5

这里实际发生的是printf' 的输出被缓冲而不是立即发送到 fd 1 ;相反,在您从main. 如果你close(newfd),你已经有效地阻止了运行时在退出时执行的自动刷新。

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

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

于 2011-12-06T06:44:39.940 回答
0

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

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

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

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

于 2011-12-06T06:46:11.613 回答
0

close, write,open是主要在linux 内核内部完成的系统调用;所以从应用的角度来看,它们是基本的原子操作。

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

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

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

于 2011-12-06T06:49:43.190 回答