0

我的意思是将文件描述符与文件指针相关联并将其用于写入。我把程序放在io.cc下面:

int main() {
    ssize_t nbytes;
    const int fd = 3;
    char c[100] = "Testing\n";
    nbytes = write(fd, (void *) c, strlen(c));     // Line #1
    FILE * fp = fdopen(fd, "a");
    fprintf(fp, "Writing to file descriptor %d\n", fd);
    cout << "Testing alternate writing to stdout and to another fd" << endl;
    fprintf(fp, "Writing again to file descriptor %d\n", fd);
    close(fd);     // Line #2
    return 0;
}

我可以交替注释第 1 行和/或第 2 行,编译/运行

./io 3> io_redirect.txt

并检查io_redirect.txt. 只要第 1 行没有被注释,它就会在io_redirect.txt预期的行中产生Testing\n。如果第 2 行被注释,我会得到预期的行

Writing to file descriptor 3
Writing again to file descriptor 3

io_redirect.txt. 但是如果没有注释,这些行就不会出现在io_redirect.txt.

  • 这是为什么?
  • 正确的使用方法是fdopen什么?

注意。这似乎是从 C/C++ 智能写入任意文件描述符的(部分)答案的正确方法 我说“部分”,因为我可以使用 C-style fprintf。我仍然想使用 C++-style stream<<

编辑:我忘记了fclose(fp)。这“关闭”了问题的一部分。

4

1 回答 1

1

这是为什么?

打开的流(“流”是打开的FILE*)是块缓冲的,因此在文件被刷新之前没有任何内容被写入目标。退出应用程序会关闭所有打开的流,从而刷新流

因为在刷新流之前关闭了底层文件描述符,所以程序的行为是未定义的。我真的建议您阅读posix 2.5.1 Interaction of File Descriptors and Standard I/O Streams(尽管如此,它是用一种可怕的语言编写的),从中:

...如果使用了两个或多个句柄,并且其中任何一个是流,则应用程序应确保它们的操作按如下所述进行协调。如果不这样做,结果是未定义的。

...

对于第一个手柄,适用以下第一个适用条件。...

  • ...

  • 如果它是一个可写入或附加的流(但也不是可读取的),则应用程序应执行 fflush() 或关闭该流。

“句柄”是文件描述符或流。“活动句柄”是您使用的最后一个句柄。

fp流是为附加到文件描述符而打开的活动句柄3。因为fp是一个活动句柄并且未刷新并且您将活动句柄切换为fdwith close(fd),所以您的程序的行为是未定义的。

我的猜测是,最有可能发生的是您的 C 标准库实现fflush(fp)main返回后调用,因为fd已关闭,一些内部write(3, ...)调用返回错误并且没有任何内容写入输出。

使用 fdopen 的正确方法是什么?

您介绍的用法是正确的使用方法fdopen

于 2020-05-18T09:42:28.103 回答