2

I've written a program that reads an whole file via fgetc:

while ((c = fgetc(f)) != EOF) { ... }

But the program is too slow. When I changed fgetc to fread,

static unsigned char buf[4096];

while ((n = fread(buf, 1, sizeof(buf), f)) > 0) { ... }

the program works about 10 times faster.

Why? As I know, fgetc is a buffered function, so it should work as fast as the second version with explicit buffer, isn't it?

  • 2
    Usually it is better to use `getc` instead of `fgetc`. For example on Windows/MinGW the `fgetc` function is extremely slow, while `getc` is implemented as a macro that directly accesses the `FILE` object's buffer and is an order of magnitude faster. – dpi Nov 05 '12 at 10:58

2 Answers2

12

You live close to a store. You need to get 100 cans of soup. Which is more efficient, 100 trips to the store getting 1 can each time or 1 trip to the store getting 100 cans? Obviously the 1 trip because each trip has overhead that takes time.

In the case of fgetc there are various kinds of overhead.

  • Function call
  • Is the file open?
  • At end of file?
  • Is the buffer empty?
  • Locking
  • etc.

These things can be done once for all the soup, or once for each can. Individually each bit of overhead is small but when repeated many times, the sum becomes significant.

walrii
  • 3,472
  • 2
  • 28
  • 47
6

With fgetc you not only get more function calls (each one has its overhead), but fgetc may also takes locks in multi-threaded application (this is mandated for instance by POSIX).

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
  • -1 : I suggest you profile a call to fgetc and report back to us how much of the time is used in the function call overhead. – mattnz Nov 04 '12 at 21:27
  • @mattnz: That's not a fair remark. Measuring the effect of locks in multi-core systems is hard, even with a good profiler. – MSalters Nov 05 '12 at 00:21