3

我是一个C初学者,尝试使用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 时,它不会自动刷新?


@编辑:

对不起,我的错误,我找到了原因,在我最初的程序中它有:

close(fd_dup);

但没有:

fclose(f_dup);

使用fclose(f_dup);后更换即可close(f_dup);

因此,如果以适当的方式关闭,重复的 fd 会自动刷新,write()&close()是一对,fwrite()&fclose()是一对,不应该混合它们。

实际上,在代码中我可以直接使用复制的 fd_dup 和write()& close(),根本不需要创建一个新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);
}
4

2 回答 2

2

dup手册页:

从这些系统调用之一成功返回后,新旧文件描述符可以互换使用。它们引用相同的打开文件描述(参见 open(2)),因此共享文件偏移量和文件状态标志;例如,如果在其中一个描述符上使用 lseek(2) 修改了文件偏移量,则另一个描述符的偏移量也会改变。

这意味着当您写入重复的文件描述符时,查找指针会更改,因此,在写入重复文件后从第一个文件描述符读取不应读取任何数据。

您正在使用fdopen创建重复流的分离 seek_ptr 和 end_ptr,这样,fd_dup停止是重复的。这就是为什么您可以在刷新和关闭流之后读取数据。

如果您不刷新第二个文件描述符,我找不到任何关于为什么您无法阅读的有力事实。我可以补充一点,它可能与sync系统调用有关。

毕竟,如果你需要一个 IO 缓冲区,你可能使用了错误的机制,检查命名管道和其他缓冲 OS 机制。

于 2014-11-03T13:54:35.663 回答
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
于 2014-11-03T14:03:19.817 回答