Buffered reading from stdin using fread in C

前端 未结 11 1473
梦谈多话
梦谈多话 2020-12-24 03:36

I am trying to efficiently read from the stdin by using setvbuf in `_IOFBF~ mode. I am new to buffering. I am looking for working examples

11条回答
  •  有刺的猬
    2020-12-24 04:22

    If you are after out-and-out speed and you work on a POSIX-ish platform, consider using memory mapping. I took Sinan's answer using standard I/O and timed it, and also created the program below using memory mapping. Note that memory mapping will not work if the data source is a terminal or a pipe and not a file.

    With one million values between 0 and one billion (and a fixed divisor of 17), the average timings for the two programs was:

    • standard I/O: 0.155s
    • memory mapped: 0.086s

    Roughly, memory mapped I/O is twice as fast as standard I/O.

    In each case, the timing was repeated 6 times, after ignoring a warm-up run. The command lines were:

    time fbf < data.file    # Standard I/O (full buffering)
    time mmf < data.file    # Memory mapped file I/O
    

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static const char *arg0 = "**unset**";
    static void error(const char *fmt, ...)
    {
        va_list args;
        fprintf(stderr, "%s: ", arg0);
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        exit(EXIT_FAILURE);
    }
    
    static unsigned long read_integer(char *src, char **end)
    {
        unsigned long v;
        errno = 0;
        v = strtoul(src, end, 0);
        if (v == ULONG_MAX && errno == ERANGE)
            error("integer too big for unsigned long at %.20s", src);
        if (v == 0 && errno == EINVAL)
            error("failed to convert integer at %.20s", src);
        if (**end != '\0' && !isspace((unsigned char)**end))
            error("dubious conversion at %.20s", src);
        return(v);
    }
    
    static void *memory_map(int fd)
    {
        void *data;
        struct stat sb;
        if (fstat(fd, &sb) != 0)
            error("failed to fstat file descriptor %d (%d: %s)\n",
                  fd, errno, strerror(errno));
        if (!S_ISREG(sb.st_mode))
            error("file descriptor %d is not a regular file (%o)\n", fd, sb.st_mode);
        data = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fileno(stdin), 0);
        if (data == MAP_FAILED)
            error("failed to memory map file descriptor %d (%d: %s)\n",
                  fd, errno, strerror(errno));
        return(data);
    }
    
    int main(int argc, char **argv)
    {
        char *data;
        char *src;
        char *end;
        unsigned long k;
        unsigned long n;
        unsigned long answer = 0;
        size_t i;
    
        arg0 = argv[0];
        data = memory_map(0);
    
        src = data;
    
        /* Read control data */
        n = read_integer(src, &end);
        src = end;
        k = read_integer(src, &end);
        src = end;
    
        for (i = 0; i < n; i++, src = end)
        {
            unsigned long v = read_integer(src, &end);
            if (v % k == 0)
                answer++;
        }
    
        printf("%lu\n", answer);
        return(0);
    }
    

提交回复
热议问题