2011-12-06 54 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