cstaticinlineextern

inline, static, extern in C99


Let me get this straight, in C99, for functions:

static: Don't produce any external symbols

extern (implicit): If there are no definitions in this translation unit, the compiler produces a reference that is resolved during linking


Now with inline. As far as I can tell, the issue is complicated due to the fact that the compiler may choose to inline, or not.


I can see this being answered in two different ways:

  1. If a compiler decides not to inline a function at some call site, then non-inline object code is generated inside the same translation unit. No external symbols are exported for this.
  2. If a compiler decides not to inline a function at some call site, then this behaves as a normal function, and there must be one translation unit that exports an external symbol and contains object code implementing the function.

static inline seems to be the answer to #1:


As far as I can tell, extern inline/inline is the answer to #2:


Is this correct?


Relevant links, yet still leave fuzzy corners:


Solution

  • Your overall understanding of this is correct.

    The translation unit that actually exports a symbol to link against must declare as extern inline. I think this is what's most confusing, since the extern keyword for normal functions behaves in almost the exact opposite way

    Yes, this is an unfortunate part of the language, but you have the right of it.


    As a minor bit of trivia (which hopefully does not confuse you), GNU gcc used to treat "inline" and "extern inline" exactly opposite the way that the C99/C11 standard treats them. In this case, GNU would interpret "inline" as "use this definition to inline with AND produce the out-of-line, externally visible definition of this function" and it would treat "extern inline" as "only use this definition for inlining; if inlining does not occur, then emit an extern reference to the function (which must be defined elsewhere)".

    For whatever reason the C99 standard chose to swap meaning of "inline" and "extern inline" and now we are stuck with it.

    Note: Quick testing shows that GNU gcc v4.9.2 will default to the "GNU" way (-fgnu89-inline) if you don't otherwise pass -std=c99/c11 or -fno-gnu89-inline. Sometime between then and GNU gcc v5.2.1 it changed because v5.2.1 will default to -fno-gnu89-inline (i.e. the standard C99/C11 way).