2016-10-12 73 views
0

在以下示例中,我們關閉默認stderr並通過fdopen()在臨時文件上使用描述符2(它是臨時文件描述符中的dup())重新打開它。然後我們write()直接到這個描述符2。我們可以安全地做到這一點,因爲這是文件上的第一次寫入操作,因此它具有空的緩衝區。在此之後,我們fprintf()到新的stderr。然後我們關閉stderr(因此,其關聯的描述符2自動關閉)。原始描述符fd保持有效。通過它,我們轉到臨時文件的開頭,讀取它的內容並將它們打印到stdout。但輸出的是亂碼:如果使用lseek(),爲什麼read()文件描述符失敗?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 

int main(void) 
{ 
    int fd; 
    char buf[200]; 
    int n; 
    char fname[] = "/tmp/tst-perror.XXXXXX"; 
    fd = mkstemp (fname); 
    fclose (stderr); 
    dup2 (fd, 2); 
    stderr = fdopen (2, "w"); 
    fd = fileno(stderr); 
    char *s = "this is a test\n"; 
    n = write(fd, s, strlen(s)); 
    fprintf(stderr, "multibyte string\n"); 
    fclose (stderr); 
// close(fd); 
// fd = open(fname, O_RDONLY); 
    lseek (fd, 0, SEEK_SET); 
    n = read (fd, buf, sizeof (buf)); 
    printf("%.*s", (int) n, buf); 
    close (fd); 
    return 0; 
} 

輸出是:

$ ./a.out 
���� 

如果我們取消對「親密」和「開放式」的線條和註釋「lseek的」行,按預期的輸出:

$ ./a.out 
this is a test 
multibyte string 

write()沒有緩衝區,stderr是當它被關閉註銷,所以 爲什麼如果我們不關閉T的輸出是亂碼他在閱讀之前提交文件?

+1

另外,要小心哪一個流'lseek'。請參閱'man 2 lseek'中的註釋,*「某些設備無法搜索,而POSIX未指定哪些設備必須支持lseek()。」*。 –

回答

1

沒有檢查函數的返回值。如果它在那裏,你會發現錯誤。

無論如何,問題是:

fd = fileno(stderr);  // getting the fd from current stderr 
    fclose (stderr);   // closing stderr 
    ... 
    lseek (fd, 0, SEEK_SET); // seeking on fd which was already closed 

在最後一次通話和後續調用fd實際上是不確定的(或者更確切地說,它引用封閉的文件描述符)。因此,對fd的任何操作都將失敗EBADF(無效的文件描述符)。

顯然,如果再次包含fd = open(...),則fd將變爲有效,並且代碼將起作用。

+0

的確,我真正的意圖是在「fileno」和「write」行中使用「fd2」。現在一切正常。 –

相關問題