8

所以我正在用 C 构建一个 Unix minishell,并正在实现输入、输出和错误重定向,并且遇到了文件问题。我在找到重定向运算符的循环中打开我的文件,并使用 open(),它返回一个 fd。然后我相应地分配孩子的 fd,并调用执行函数。

当我的 shell 只是出去寻找程序并使用 execvp() 执行它们时,我没有太多问题。唯一的问题是在提示输入下一个命令行之前,我是否需要在文件描述符上调用 close()。我担心 fd 泄漏,但不完全了解它是如何工作的。

使用内置命令时出现了我真正的问题。我有一个名为“read”的内置命令,它接受一个参数,一个环境变量名称(可能是一个尚不存在的)。Read 然后提示输入一个值,并将该值分配给变量。这是一个例子:

% read TESTVAR
test value test value test value
% echo  ${TESTVAR}
test value test value test value

好吧,可以说我尝试这样的事情:

% echo here's another test value > f1
% read TESTVAR < f1
% echo  ${TESTVAR}
here's another test value

这很好用,请记住 read 在父进程内执行,我不使用 execvp 调用 read,因为它是内置的。读取使用gets,它需要一个流变量,而不是fd。因此,在 irc 论坛上闲逛了一下之后,我被告知使用 fdopen,从文件描述符中获取流。所以在调用 get 之前,我调用:

rdStream = fdopen(inFD, "r");

然后打电话

if(fgets(buffer, envValLen, rdStream) != buffer) 
{
    if(inFD) fclose(rdStream);
    return -1;
}
if(inFD) fclose(rdStream);

如您所见,目前我正在使用 fclose() 关闭流,除非它等于标准输入(即 0)。这是必要的吗?我需要关闭流吗?还是只是文件描述符?或两者?我很困惑我应该关闭哪个,因为它们都以不同的方式引用同一个文件。目前我没有关闭 fd,但我认为我绝对应该。我只是希望有人帮助确保我的 shell 没有泄漏任何文件,因为我希望它能够在单个会话中执行数千个命令而不会泄漏内存。

谢谢,如果你们想让我发布更多代码,请询问。

4

2 回答 2

11

The standard says:

The fclose() function shall perform the equivalent of a close() on the file descriptor that is associated with the stream pointed to by stream.

So calling fclose is enough; it will also close the descriptor.

于 2012-12-03T20:30:04.133 回答
2

FILE是标准 C 库中的缓冲对象。当你这样做时fclose(标准 C 函数),它最终会调用close(Unix 系统函数),但只有在确保 C 库缓冲区被刷新之后。所以,我想说,如果你使用fopen然后fwrite你应该使用fclose,而不仅仅是close,否则你可能会丢失一些数据。

于 2012-12-03T20:41:37.400 回答