Search code examples
cheader-filesjsmn

Aren't header-only C "libraries" wasteful?


I'm looking at a header-only C "library": https://github.com/zserge/jsmn/blob/master/jsmn.h

As far as I can understand, this code will be compiled into every object file where the .c file includes jsmn.h, wasting space.

(The file's function definitions are inside #ifndef JSMN_HEADER, so you could use this as a "traditional" header file by defining JSMN_HEADER.)

  • Why hasn't it been written as a "traditional" .c and .h pair?
  • Is the linker clever enough to dedup function identical definitions between object files? I would have expected "duplicate symbol" errors.
  • What advantage does putting code in headers give in C? (Not C++.)
  • From where do you get the function definitions if you use #define JSMN_HEADER before importing?
  • Is jsmn.h being header-only a clever trick, from which I can learn?

Solution

  • The header expands into one of the following, depending on the macros defined:

    1. No macros — function definitions (public functions are non-static, private ones are).
    2. JSMN_HEADER — function declarations (for public functions only).
    3. JSMN_STATICstatic function definitions (for both private and public functions).

    If only a single TU needs the library, you can freely choose between (1) and (3).

    If more than one TU needs the library, you need (1) in one of the TUs and (2) in all others. Then the only thing that's "wasted" is preprocessor time for skipping function definitions for (2), but it shouldn't matter since they're so tiny.

    In this case, trying to go with (1) for all TUs would give you "duplicate symbol" linker errors. Trying to go with (3) for all TUs would silently duplicate the symbols, which would be wasteful.

    Why hasn't it been written as a "traditional" .c and .h pair?

    For supposed convenience of distributing and using the library.

    Is the linker clever enough to dedup function identical definitions between object files? I would have expected "duplicate symbol" errors.

    It's probably not clever enough, but it doesn't need to be.

    You're expected to define the macros so that only a single TU has the definitions.

    What advantage does putting code in headers give in C?

    Less source files to distribute.

    From where do you get the function definitions if you use #define JSMN_HEADER before importing?

    From your other TU that didn't define this macro before including the header.

    Is jsmn.h being header-only a clever trick, from which I can learn?

    Yes.