Search code examples
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.

  • If the compiler decides to inline, clearly the implementation must be visible at compile-time
  • If the compiler decides not to inline, what function gets linked, and in which translation unit does that code live?

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:

  • If the compiler decides to inline a static inline function, then go for it. The static storage specifier is consistent with its use with non-inline functions in that no external symbols are produced. Since this is the case, if the compiler decides to inline a static inline function at every call site within a translation unit, it need not generate stand-alone object code.
  • If the compiler decides not to inline a static inline function at some call site, then it can generate stand-alone object code inside the translation unit, and no external symbols will be exported for it.

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

  • All inline (without extern or static) behave like #2. If the compiler doesn't actually inline them, then at link time an external implementation needs to be linked-in.
  • 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

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).