2014-11-03 107 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