C 什么时候打电话?

C 什么时候打电话?,c,windows,pipe,popen,pclose,C,Windows,Pipe,Popen,Pclose,我有一个函数,在这个函数中我调用了几次open 如果\u popen返回NULL我是否需要在函数返回之前调用\u pclose 我已经标记了3个我认为可能需要调用\u pclose的位置 我必须在这些位置中的哪个位置呼叫\u pclose bool theFunction() { FILE* pPipe; char buffer[1000]; if( (pPipe = _popen("dir", "rt")) == NULL ) { //locat

我有一个函数,在这个函数中我调用了几次open

如果
\u popen
返回
NULL
我是否需要在函数返回之前调用
\u pclose

我已经标记了3个我认为可能需要调用
\u pclose
的位置

我必须在这些位置中的哪个位置呼叫
\u pclose

bool theFunction()
{
    FILE* pPipe;
    char buffer[1000];
    if( (pPipe = _popen("dir", "rt")) == NULL )
    {
        //location 1
        _pclose(pPipe);
        return false;
    }

    while(fgets(pipeBuffer, maxBufferSize, pPipe))
    {
        printf(pipeBuffer);
    }

    if( (pPipe = _popen("cls", "rt")) == NULL )
    {
        //location 2
        _pclose(pPipe);
        return false;
    }

    //location 3
    _pclose(pPipe);

    return true;
}

简单:如果可以打开但不再需要,请关闭管道。因此:

bool theFunction()
{
    FILE* pPipe;
    char buffer[1000];
    if( (pPipe = _popen("dir", "rt")) == NULL )
    {
        return false;
    }

    while(fgets(pipeBuffer, maxBufferSize, pPipe))
    {
        printf(pipeBuffer);
    }

    // The fact that you have to close it here in the middle of nowhere
    // should ring a bell that you need to think about separation of concern 
    _pclose(pPipe);

    if( (pPipe = _popen("cls", "rt")) == NULL )
    {
        return false;
    }

    _pclose(pPipe);
    return true;
}

如果成功使用
popen
创建管道,但未调用
pclose
,则不会释放
文件
对象占用的内存。更糟糕的是,还有外部可见的后果。由
popen
创建的子进程可能会徘徊。当您使用
popen
时,将使用
fork
创建一个进程。在调用
pclose
之前,可能不会发生相应的
waitpid
。(我相信这是一个典型的、显而易见的实现,这也是我为其他编程语言实现类似popen的函数的方式。)

尽管Win32没有
fork
wait
,但Microsoft C库的
\u popen
中可能存在类似的资源问题。
文件
管道句柄可能有一个进程的内部Win32句柄,在调用
\u pclose
之前,该句柄不受
关闭句柄的约束。加上与该进程通信的其他资源,如Win32管道。如果你不关闭管道,那么你就泄漏了这些资源

关于传递空指针。这是对原始POSIX函数的否定。如果对空指针调用了
pclose
,则不会定义该行为。POSIX说“[i]如果pclose()的参数流不是指向popen()创建的流的指针,则pclose()的结果是未定义的。”(空指针不是指向流的指针,即使它是由
popen
返回的)

Microsoft允许使用空指针调用
\u pclose
。这就是,
\u pclose
返回-1并将
errno
伪变量设置为
EINVAL


如果你想输入基于这些函数的代码,这是要考虑的。

你不能关闭任何你不能打开的东西。请看第一个示例,您正试图关闭
NULL
。请从
\u pclose()
的角度来考虑这个问题。。。如果您传递了它
NULL
,它怎么知道要关闭什么?好的,如果它看起来像一个糟糕的问题,那么很抱歉。虽然我知道pPipe在这些点上是
Null
,但我对管道和这些命令还是新手。我这样问是因为我想确保在
\u pclose
中没有其他东西被清理。谢谢你的快速回复。你查过手册了吗?是的,我已经阅读了手册页。为什么您第一次调用
\u pclose
的位置是您的位置?因为此后您将覆盖
pPipe
,因此您将丢失第一个管道的值,并且无法再关闭它。