2014-11-03 150 views
3

我是一個C初學者,試圖用dup(),我寫了一個程序來測試這個函數,結果與我所期望的有點不同。dup()和緩存刷新

代碼

// unistd.h, dup() test 

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

extern void dup_test(); 

int main() { 
    dup_test(); 
} 

// dup()test 
void dup_test() { 
    // open a file 
    FILE *f = fopen("/tmp/a.txt", "w+"); 
    int fd = fileno(f); 
    printf("original file descriptor:\t%d\n",fd); 

    // duplicate file descriptor of an opened file, 
    int fd_dup = dup(fd); 
    printf("duplicated file descriptor:\t%d\n",fd_dup); 
    FILE *f_dup = fdopen(fd_dup, "w+"); 

    // write to file, use the duplicated file descriptor, 
    fputs("hello\n", f_dup); 
    fflush(f_dup); 
    // close duplicated file descriptor, 
    fclose(f_dup); 
    close(fd_dup); 

    // allocate memory 
    int maxSize = 1024; // 1 kb 
    char *buf = malloc(maxSize); 

    // move to beginning of file, 
    rewind(f); 
    // read from file, use the original file descriptor, 
    fgets(buf, maxSize, f); 
    printf("%s", buf); 

    // close original file descriptor, 
    fclose(f); 

    // free memory 
    free(buf); 
} 

程序試圖通過複製FD寫,然後關閉複製FD,然後嘗試通過原有的FD閱讀。

我預料當我關閉重複的fd時,io緩存將自動刷新,但不是,如果我刪除代碼中的fflush()函數,原始fd將無法讀取由已經關閉的重複fd。

我的問題是

這是否意味着當接近重複的FD,它不會自動執行刷新?


@Edit:

我很抱歉,我的錯,我找到了原因,在我最初的計劃有:

close(fd_dup); 

,但沒有:

fclose(f_dup); 

使用後fclose(f_dup);來代替close(f_dup); 有用。

因此,複製FD做,如果關閉以適當的方式自動沖洗,write() & close()是一對,fwrite() & fclose()是一對,不應該將它們混合。

其實,在代碼中,我可以有使用與write() & close()複製的fd_dup直接,也沒有必要建立一個新的FILE可言。

因此,代碼可能僅僅是:

// unistd.h, dup() test 

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

#define BUF_SIZE 1024 // 1 kb 

extern void dup_test(); 

int main() { 
    dup_test(); 
} 

// dup()test 
void dup_test() { 
    // open a file 
    FILE *f = fopen("/tmp/a.txt", "w+"); 
    int fd = fileno(f); 
    printf("original file descriptor:\t%d\n",fd); 

    // duplicate file descriptor of an opened file, 
    int fd_dup = dup(fd); 
    printf("duplicated file descriptor:\t%d\n",fd_dup); 

    // write to file, use the duplicated file descriptor, 
    write(fd_dup, "hello\n", BUF_SIZE); 
    // close duplicated file descriptor, 
    close(fd_dup); 

    // allocate memory 
    char *buf = malloc(BUF_SIZE); 

    // move to beginning of file, 
    rewind(f); 
    // read from file, use the original file descriptor, 
    fgets(buf, BUF_SIZE, f); 
    printf("%s", buf); 

    // close original file descriptor, 
    fclose(f); 

    // free memory 
    free(buf); 
} 
+2

您可能想對程序進行「strace」以檢查它實際執行的是什麼系統調用。在我的系統上,你的程序總是打印'hello'。我認爲可能發生的事情是'f_dup'被刷新,但'f'在此之前(在'fopen')查看您的文件。 – zch 2014-11-03 13:55:07

+0

因爲你有'fdopen'你的'fd',你應該主要操作的對象是'FILE *'。他們基本上是同一件事,不要兩次關閉同一件事。而且,你對'FILE *'和'int'的意思是'fd'。 'FILE *'是文件流,它是一個標準的表示,所以它是交叉平臺。 'fd'實際上是'int',是文件描述符表的索引號,是* nix系統的特徵。 – HuStmpHrrr 2014-11-03 14:05:49

+0

@zch Thx,strace是一個偉大的工具! – 2014-11-03 14:09:06

回答

1

我真的不明白你的問題。我在Microsoft VC2008下測試了它(必須用io.h替換unistd.h)和gcc 4.2.1。

我註釋掉fflush(f_dup),因爲它以前是密切和close(fd_dup);因爲文件描述符已經關閉,所以這段代碼現在看起來沒有用:

// write to file, use the duplicated file descriptor, 
fputs("hello\n", f_dup); 
// fflush(f_dup); 
// close duplicated file descriptor, 
fclose(f_dup); 
// close(fd_dup); 

而且它工作正常。我可以在兩個系統上使用:

original file descriptor:  3 
duplicated file descriptor:  4 
hello 
+0

謝謝,我的錯誤,在更新的問題中描述的原因。 – 2014-11-03 14:27:48

2

dup手冊頁:

從這些系統調用的一個,舊的和新的文件描述符也許成功返回後可互換使用。它們引用相同的打開文件描述(請參見打開(2)),從而共享文件偏移量和文件狀態標誌;例如,如果在其中一個描述符上使用lseek(2)修改了文件偏移量,則另一個偏移量也會發生更改。

這意味着當您寫入重複的文件描述符時,seek指針被改變,所以在寫入重複之後從第一個文件描述符讀取不應該讀取任何數據。

您正在使用fdopen創建複製流的分離的seek_ptr和end_ptr,這樣,fd_dup停止成爲重複項。這就是爲什麼你可以在沖洗和關閉流之後讀取數據。

我找不到任何有關爲什麼如果不刷新第二個文件描述符就無法讀取的強大事實。我可以補充說它可能與sync系統調用有關。畢竟,如果你需要一個IO緩衝區,你可能會使用錯誤的機制,檢查命名管道和其他緩衝OS機制。

+0

我在讀之前寫完後倒帶(),所以尋找指針不成問題。無論如何,感謝您的建議,代碼只是試圖找出dup()的功能,在現實世界中,程序可能會使用不同的方法。 – 2014-11-03 14:04:53