2017-04-03 62 views
0

我有一個奇怪的問題,使用dup2系統調用將STDOUT重定向到一個文件。奇怪的問題重定向輸出使用dup2系統調用

我使用的是2個功能,我發現在這裏: In C how do you redirect stdin/stdout/stderr to files when making an execvp() or similar call?

下面是一個簡單的程序,我寫來測試功能後,我有錯誤。 程序按預期工作並將輸入寫入文件。

int fd; 
fpos_t pos; 

int main(){ 
    while(1){ 
     char input[100]; 
     printf("Please enter text: "); 
     gets(input); 
     printf("\nString = %s\n", input); 

     switchStdout("test.txt"); 

     puts("THIS TEXT SHOULD REDIRECT\n"); 
     printf("String(file) = %s\n", input); 

     revertStdout(); 

     puts("This should come before the gets() ??\n"); 
    } 
    return 0; 
} 

void switchStdout(const char *newStream) 
{ 
    fflush(stdout); 
    fgetpos(stdout, &pos); 
    fd = dup(fileno(stdout)); 
    freopen(newStream, "w", stdout); 
    return; 
} 

void revertStdout() 
{ 
    fflush(stdout); 
    dup2(fd, fileno(stdout)); 
    close(fd); 
    clearerr(stdout); 
    fsetpos(stdout, &pos); 
} 

調用revertStdout()函數後,程序似乎掛起。

我意識到,事實上,程序在打印之前調用了gets()「這應該在gets()??之前出現」

輸入文本後,程序打印跳過的行。

下面是我在大膽進入終端輸出:

請輸入文字:你好!!!!

String = Hello !!!!

爲什麼我能夠在此輸入?
這應該在gets()之前?

請輸入文字:

String =爲什麼我能夠在此輸入?

對不起,很長的職位。程序按預期寫入文件。

感謝任何人都可以提供的幫助。

+0

http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used –

+0

如果你想重新打開一個流來使用一個不同的描述符或句柄,你可能需要'fdopen()'。它不在標準庫中,但Unix,Windows和OSX都支持它。 – Davislor

回答

0

基本上,當你偷偷溜到標準庫的後面時,會發生這種情況。

報價man setbuf

通常所有文件都是塊緩衝。當一個文件發生第一次I/O操作時,調用malloc(3),並獲得一個緩衝區。如果一個流指的是一個終端(正如stdout通常那樣),它是行緩衝的。

所以,你的stdout開始是指你的終端,並且是線路緩衝的。然後你把它指向一個文件,所以(作爲重新打開流的一部分),它變成塊緩衝。那麼你dup2的FD,所以現在它再次指的是終端,但它仍然是相同的流;標準庫不知道你已經達到了stdout的內容並改變了它所指的內容。所以它保持塊緩衝,導致意想不到的行爲。

在第一個輸出導致未定義行爲後更改緩衝流,儘管如果緩衝區爲空(因爲它將在調用fflush之後),有些C庫實現也是如此。你不應該指望這種行爲。但是,您可以在dup2之後立即再次傳輸流,將NULL第一個參數傳遞給freopen,從而爲標準庫提供重新初始化的機會。

由於freopen有效地關閉了流,所以不需要中的fflush調用。如果將freopen添加到revertStdout,它將重置錯誤和文件結束指示符,以便您可以刪除對clearerr的呼叫。

+0

在dup2修復它後添加freopen(NULL,「w」,stdout)。謝謝! –