2011-12-06 29 views
2

这里是我的代码:为什么close()系统调用刷新输出?

#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只是打印“堆栈溢出”到文件(),而不是写()系统调用。

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

close(newfd) 

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

这是什么原因?

+0

例如,为了不太频繁地写入磁盘。效率。 – Beginner

+0

为什么不使用'fprintf(fd,fmt,...)'?我不确定试图重用fd = 1是一个好主意,甚至是定义。 – jedwards

+0

杰德华兹,我其实是想知道为什么这不工作:) – Dinesh

回答

5

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

如果您在close(newfd)之前明确指定了fflush(stdout),那么您的输出应该出现在文件中。顺便说一句,如果你想重定向一个特定的文件描述符,有一个替代系统调用dup2(oldfd, 1),这使得fd 1重复oldfd,关闭fd 1,如果它以前打开。

+0

谢谢杰弗里汉坦:) – Dinesh

0

当你直接使用文件描述符时,你会想要避免使用C stdio函数,如printf。从stdio层下改变底层文件描述符似乎充满了危险。

如果您改变printf以下几点:

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

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

0

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

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

之前exit -ing(例如,从main返回),标准库和环境(特别是在crt*.o代码调用你main)正在执行由atexit登记的功能;并且标准I/O在退出时注册到fflush的呼叫(排序)。所以stdout在退出时是fflush。如果你的主描述符为close,那么刷新失败并且什么也不做。

我认为你不应该混合stdio和原始write -s到相同的写描述符。考虑使用fdopen or freopen