2

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?
fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 3
    Looking at the code, it seems all the functions are static, so there's no multiple definition issue. – mediocrevegetable1 Oct 16 '21 at 07:02
  • @mediocrevegetable1 Thanks, I hadn't spotted that. That leaves just the issue of bloat due to multiple versions in multiple .o files. As this is an embedded-focused library I'm probably missing something here. – fadedbee Oct 16 '21 at 07:04
  • Obviously they are wasteful wrt code size. But waste is what most software is. Linkers/compilers are rarely smart to deduplicate this. MSVC can do this for some cases if LTCG is enabled. –  Oct 16 '21 at 07:05
  • @StaceyGirl This is an embedded-focused libary; a context where every byte counts. It's much more likely that my understanding is at fault, vs this strategy actually causing bloat. – fadedbee Oct 16 '21 at 07:07
  • @fadedbee There will no bloat if you only use it in a single .c file. So it still can be useful. Also embedded is not _that_ focused on binary size - most embedded software is still horrible, just like any other software. –  Oct 16 '21 at 07:08
  • that's oldtimey way to implement "inline" functions in C. static makes them internal linkage and optimization (hopefully) would inline them, while linker would skip unused ones.And I saw this done alot in embedded software, some embedded compilers use full program optimization. This is actually may be important that deduplication_never_ would happen so every module got independent function , call to which can be monitored. – Swift - Friday Pie Oct 16 '21 at 07:23
  • 2
    @mediocrevegetable1 The public functions are non-static, unless you define `JSMN_STATIC`. You're not supposed to use it to duplicate the symbols. Rather, you're supposed to use `JSMN_HEADER` in all TUs except one, so only one TU has the definitions. – HolyBlackCat Oct 16 '21 at 08:59

1 Answers1

3

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.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207