类似于pipe(3)的函数,但返回FILE *

时间:2019-01-13 06:32:03

标签: c posix

是否有类似int pipe(int pipefd[2])的函数但返回了FILE指针?我知道我可以FILE * fdopen(int)既使用文件描述符,也知道当我使用int fclose(FILE *)指针FILE时,它将关闭基础文件描述符,因此我不需要跟踪它们,但最好完全使用文件描述符或FILE指针。

int fpipe(FILE * pipes[2]) {
  int result; 
  int pipefd[2];
  FILE * pipe[2];

  if (0 != (result = pipe(pipefd))) {
    return result;
  }

  if (NULL == (pipe[0] = fdopen(pipefd[0], "r"))) {
    close(pipefd[0]);
    close(pipefd[1]);
    return errno;
  }

  if (NULL == (pipe[1] = fdopen(pipefd[1], "w"))) {
    fclose(pipe[0]);
    close(pipefd[1]);
    return errno;
  }

  pipes[1] = pipe[1];
  pipes[0] = pipe[0];
  return 0;
}

2 个答案:

答案 0 :(得分:5)

您的fpipe()函数接近所需的功能,并且没有标准函数可以完成相同的工作,因此您需要编写一些东西。没有这种标准功能的主要原因是,大多数情况下,您最终会分叉,然后使用dup()dup2()并最终使用exec*()函数,因此实际上并没有太多功能大多数情况下,受益于文件流。

如评论中所述,您需要确定在成功和错误时返回什么,并相应地管理errno。有两种合理的设计(两者都有先例):

  1. 该函数成功返回0,失败返回-1,并在errno变量中提供更详细的错误信息(经典函数调用技术:请参见open(),{{ 1}},close()read(),...)。
  2. 该函数在成功时返回write(),在失败时返回错误号(不修改0),这是POSIX线程(errno)函数使用的技术。

两种设计都会在发生错误时使pthreads数组处于不确定状态。这不是不合理的。在调用pipes[]之前,参数数组不应指向有价值的文件流,因为如果调用成功,则值将丢失。

请记住,没有标准的C或POSIX库函数将fpipe()设置为零。 (请参阅POSIX errno)。

以下是两种设计,它们是通过编译器命令行上是否存在errno来选择的:

-DUSE_PTHREAD_COMPATIBLE_DESIGN

在函数的第一个变体中,由于#include <errno.h> #include <stdio.h> #include <unistd.h> extern int fpipe(FILE *pipes[2]); // Should be in a header #ifndef USE_PTHREAD_COMPATIBLE_DESIGN // Design 1 - return -1 on failure and set errno int fpipe(FILE *pipes[2]) { int pipefd[2]; if (pipe(pipefd) != 0) return -1; if ((pipes[0] = fdopen(pipefd[0], "r")) == NULL) { close(pipefd[0]); close(pipefd[1]); return -1; } if ((pipes[1] = fdopen(pipefd[1], "w")) == NULL) { fclose(pipes[0]); close(pipefd[1]); return -1; } return 0; } #else // Design 2 - return error number on failure and don't modify errno int fpipe(FILE *pipes[2]) { int saved_errno = errno; int rc = 0; int pipefd[2]; if (pipe(pipefd)) != 0) rc = errno; else if ((pipes[0] = fdopen(pipefd[0], "r")) == NULL) { rc = errno; close(pipefd[0]); close(pipefd[1]); } else if ((pipes[1] = fdopen(pipefd[1], "w")) == NULL) { rc = errno; fclose(pipes[0]); close(pipefd[1]); } errno = saved_errno; return rc; } #endif /* USE_PTHREAD_COMPATIBLE_DESIGN */ 块的主体始终以if结尾,因此下一个块无需使用return。对于第二种变体,else if块不会返回,因此if很重要。 C可以测试分配结果的能力在这里有很大帮助。

如果愿意,可以在第二个变体的返回值之前添加else if。您必须将这些分配放在其他设计的更多位置。实际上,我可能会在输入时将值设置为if (rc != 0) pipes[0] = pipes[1] = NULL;,然后仅在初始化时将NULL重置为NULL,而没有初始化pipes[0]

答案 1 :(得分:1)

pipe(2)系统调用提供文件描述符(通过在不失败时填充其中两个的数组)。您应该测试pipe是否失败。

fdopen(3)函数从file descriptor产生FILE*流。

您只需要根据需要将两者结合即可。

有一个popen(3)函数(您将使用pclose而不是fclose)。

某些系统(但不是Linux)也具有p2open