Wrap POSIX File Descriptors to C FILE Streams
This article explains how to bridge low-level POSIX I/O and standard
C library buffered I/O by converting raw file descriptors into
FILE* streams. In C, while POSIX operations like
open(), pipe(), or socket() yield
integer file descriptors, higher-level stream functions like
fprintf() or fgets() require FILE
pointers. The POSIX standard provides the dedicated function
fdopen() to achieve this association without duplicating
system resources.
The Primary Function:
fdopen()
The standard function used to wrap an open POSIX file descriptor into
a buffered FILE stream is fdopen(). It is
declared in <stdio.h> as part of the POSIX standard
specification:
FILE *fdopen(int fd, const char *mode);The function takes two parameters:
fd: An existing, valid open file descriptor returned by system calls such asopen(),socket(),pipe(), oraccept().mode: A string specifying the stream access mode (e.g.,"r","w","a","r+","w+","a+").
If successful, fdopen() returns a pointer to a valid
FILE object. If it fails, it returns NULL and
sets errno to indicate the error.
Mode Compatibility
The mode argument supplied to fdopen() must
match the access permissions of the underlying file descriptor:
- If the descriptor was opened read-only (
O_RDONLY), the mode must begin with"r". - If the descriptor was opened write-only (
O_WRONLY), the mode must begin with"w"or"a". - If the descriptor was opened read/write (
O_RDWR), the mode can include"+".
Providing a mode incompatible with the file descriptor's open flags results in undefined behavior or failure.
Resource Ownership and Lifecycle
When a stream is created using fdopen(), the resulting
FILE* object assumes ownership of the file descriptor:
- Calling
fclose(stream)will automatically close the underlying integer file descriptorfd. You should not manually invokeclose(fd)afterfclose(). - If the program needs to retain direct descriptor access alongside
stream access, avoid calling
fclose(), or duplicate the descriptor usingdup()prior to wrapping it.
Extracting Descriptors with
fileno()
To perform the reverse operation—extracting the raw POSIX file
descriptor from an active FILE* stream—use the POSIX
function fileno():
int fileno(FILE *stream);This returns the integer file descriptor associated with the given stream, enabling seamless transitions between buffered stream operations and low-level system calls when necessary.