【问题标题】:how to tell if a stream is closed in C before calling fclose()在调用 fclose() 之前如何判断流是否在 C 中关闭
【发布时间】:2026-01-19 08:25:01
【问题描述】:

我有一个失败的 C 程序,我已将其范围缩小为 fork()ed 子试图关闭 stdout 和 stderr,它们在调用 fork() 之前已被其父进程关闭 - 我假设这些流已通过到子进程。

在尝试使用 fclose(stdout) 之类的方法关闭流之前,我如何判断流是否已在 C 中关闭

【问题讨论】:

    标签: c++ c stream


    【解决方案1】:

    UNIX 上的 C 程序期望在启动时打开文件描述符 0、1 和 2。如果您不希望它们去任何地方,请打开 /dev/nulldup 到这些文件描述符。

    【讨论】:

      【解决方案2】:

      如果您在该级别工作,您可能不应该使用 C 标准库的缓冲 FILE 指针 (stdin & co),而应该使用底层的 file descriptor 整数本身。

      您应该能够执行一些无害的操作,例如在文件上使用@987654322@ 来检测底层描述符是否有效。

      【讨论】:

        【解决方案3】:

        您可以使用 ftell() 来检查。 如果它返回 -1,则您的流大部分已关闭。

        【讨论】:

          【解决方案4】:

          在调用 fclose() 之后,任何使用 流导致未定义的行为。

          所以如果它是 FILE* 标准输出,你就不能再使用stdout,甚至不能检查它是否有效/打开。

          你可以直接使用标准输出的文件描述符,它是 fd 1 。

          struct stat stbuf;
          if(fstat(1,&stbuf) == -1) {
            if(errno == EBADF) {
              stdout isn't open/valid
            }
          }
          

          【讨论】:

          • 要么我错过了什么,要么这不起作用?我尝试在添加的 else{} 子句中调用 fclose()(意味着 fstat 的结果不是 -1)并注意到它从未关闭流 - 即使我确定它是有效的并且打开
          • 看起来确实不可靠,是的。在我的系统上,发生的是 fclose(stdout);确实关闭了fd。但是,无论出于何种原因, fclose 都会触发 "/usr/share/nls/nls.alias" 的加载,它现在获得 fd 1,因为它是免费的 - 并且以下 fstat 成功 - 但现在指的是 /usr/share/ nls/nls.alias”。如果以不同的顺序调用事情,事情可能会有所不同。在“strace”下运行你的程序,看看会发生什么。你最好接受 cafs 的建议,永远不要关闭 stdin/out/err ,而是将它们重定向到 /dev/null
          最近更新 更多