Search code examples
cioposixfopen

fopen vs open (in C) in POSIX


After this question , a doubt comes up:

Once fopen() is faster than open() (for sequential writing/ready operations at least), the former is a library and the latter is a system call, what system call does fopen() do in a POSIX compilant OS?


Solution

  • It calls open.

    fopen itself is not faster than open; it can't be, it's open plus some extra work. The performance benefit, described in the linked question, is from the "buffering" done by the FILE object over its entire lifecycle. The actual optimization is to call the write primitive fewer times, providing more data each time.

    Here is a simple way to demonstrate the effect: Compile this program.

    #define _XOPEN_SOURCE 700
    #include <stdlib.h>
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
        if (argc != 3) return 1;
        long count = atol(argv[1]);
        long chunk = atol(argv[2]);
        if (count < 1 || chunk < 0) return 1;
    
        FILE *sink = fopen("/dev/null", "wb");
        if (!sink) return 1;
    
        if (chunk) {
            char *buf = malloc(chunk);
            if (!buf) return 1;
            if (setvbuf(sink, buf, _IOFBF, chunk)) return 1;
        } else {
            if (setvbuf(sink, 0, _IONBF, 0)) return 1;
        }
    
        while (count--) putc_unlocked('.', sink);
        return 0;
    }
    

    It takes two arguments: the total number of bytes to write, and the size of the output buffer, in that order. Run it with various values of both parameters and time its performance; you should see that, e.g.

    ./a.out $((1024*1024*128)) 1
    

    is much slower than

    ./a.out $((1024*1024*128)) 8192
    

    The first number will need to be quite large for the difference to be measurable. Once you've played around with that for a while, run

    strace ./a.out 50 1
    

    and

    strace ./a.out 50 50
    

    to understand the difference in what's going on at the system call level. (If you are using an OS other than Linux, replace strace with whatever the equivalent command is for that OS.)