是否有类似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;
}
答案 0 :(得分:5)
您的fpipe()
函数接近所需的功能,并且没有标准函数可以完成相同的工作,因此您需要编写一些东西。没有这种标准功能的主要原因是,大多数情况下,您最终会分叉,然后使用dup()
或dup2()
并最终使用exec*()
函数,因此实际上并没有太多功能大多数情况下,受益于文件流。
如评论中所述,您需要确定在成功和错误时返回什么,并相应地管理errno
。有两种合理的设计(两者都有先例):
0
,失败返回-1
,并在errno
变量中提供更详细的错误信息(经典函数调用技术:请参见open()
,{{ 1}},close()
,read()
,...)。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。