Frustrated by the general answers so far (I can RTFM , tyvm), I have carefully examined this, step by step through and reading the glibc source.
In glibc, pclose() directly calls fclose() with no additional effect, so the 2 calls are the same. In fact, you could use pclose() and fclose() interchangeably. I'm sure this is just a coincidence in the evolutionary implementation, and using pclose() to close the FILE * returned from popen() still recommended.
The magic is in popen() . FILE * in glibc contains a jump table with pointers to the appropriate functions to handle calls such as fseek() , fread() and the relevance of fclose() . Calling popen() uses a different jump table than the one used by fopen() . The close element in this jump table points to the special function _IO_new_proc_close , which calls waitpid() on the pid stored in the area pointed to by FILE * .
Here is the corresponding call stack in my version of glibc, which I annotated with notes on what was going on:
// linux waitpid system call interface
Thus, when using popen() returned FILE * should not be closed, even if you dup() its file descriptor, because it will be blocked until the child process completes. Of course, after that you will be left with a file descriptor in the channel, which will contain everything that the child process could write () before it was completed.
Not fread() with the file pointer returned with popen() , the base channel will not be affected, it is safe to use the file descriptor fileno() and will end by calling pclose() .
source share