【问题标题】:Correct way of using fdopen使用 fdopen 的正确方法
【发布时间】:2020-05-17 19:34:53
【问题描述】:

我的意思是将文件描述符与文件指针相关联并使用它来写入。 我在下面整理了程序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的正确使用方法是什么?

注意。 这似乎是对Smart-write to arbitrary file descriptor from C/C++ 的(部分)回答的正确方法 我说“部分”是因为我可以使用 C 风格的fprintf。 我仍然想使用 C++ 风格的stream&lt;&lt;

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

【问题讨论】:

  • 如果您发现了您的问题之一,您可以删除它而不是添加更正吗?
  • @tadman - 我检查过,fclose(fp):fflush(fp): close(fd): 工作正常。它们是等价的吗?
  • 您混合了缓冲和无缓冲的写入,这总是一个问题。这里的用例是什么?您应该选择一种且只有一种方法与实际代码中的文件句柄进行交互。只要你保持一致,任何方法都可以。如果您需要从一种方法切换到另一种方法,请确保在切换后刷新并避免写入。
  • @tadman - 太好了。相关:stackoverflow.com/a/61708362/2707864
  • @JohnKugelman - 因为我认为我理解了问题的答案。但我觉得我没有一个权威的答案,cmets 发帖说明了这一点。我觉得,在这种情况下,它更有用。在其他情况下,我当然会编辑以删除问题。

标签: c++ fcntl fdopen


【解决方案1】:

这是为什么呢?

打开的流(“流”是打开的FILE*)是块缓冲的,因此在文件被刷新之前没有任何内容被写入目标。退出应用程序closes all open streams,其中flushes the stream

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

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

...

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

  • ...

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

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

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

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

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

你介绍的用法是fdopen的正确使用方式。

【讨论】:

  • 所以有一些我可以查询/检查的错误?捕捉它的正确方法是什么?
  • 未定义行为意味着您的程序的行为未定义,任何事情都可能发生。不可能检查未定义的行为,因为一旦发生,任何事情都可能发生,所以唯一的方法是编写程序以便定义行为。从实际角度来看,我鼓励使用 glibc 源代码确认fclose(或fflush)在这种情况下返回非零值。
  • 但是你说“一些内部 write(3, ...) 调用返回一个错误......”我猜这不是未定义的行为。
  • That is not undefined behavior 该标准字面意思是:the result is undefined。就我而言,实现的作用无关紧要,your program opens gate to hell and spawns nasal demons
猜你喜欢
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
  • 2015-12-17
  • 2012-02-23
  • 2013-01-09
  • 2010-12-28
  • 2012-04-26
  • 2014-10-24
相关资源
最近更新 更多