0

I'm quoting these lines from this link: Is "inline" without "static" or "extern" ever useful in C99?

To make inline work in c99 we need to do the following:

non-extern "inline" definition goes in the header (but does not necessarily result in any code generation at all), while the "extern inline" declaration goes in the .c file and actually causes the code to be generated.

The above behaviour has been questioned about but there is no answer I could find.

It just seems the C designer were high at the time. How does the above rule work? In every other C style coding definition goes in header and declaration goes in source file. But here it's backward and a declaration causes code generation?

Josh
  • 67
  • 2
  • `inline`, like `register`, is more of a polite request than a directive the compiler must obey. I'm not sure why you'd want to `extern inline` in the first place. The [GNU compiler docs](https://www.gnu.org/software/gnulib/manual/html_node/extern-inline.html) hint at how confusing this situation is. – tadman Jun 16 '20 at 01:10
  • as all functions in C by default are `extern` it is an equivalent of `int add(int a , int b); inline int add(int a , int b){ return a+b; }` from your previous question. It was explained there – 0___________ Jun 16 '20 at 01:29

2 Answers2

2

You're saying that "function definitions should go to translation units"... yes, but an inline function is such that it is supposed to be inlinable in another translation unit. And the C compilers commonly do not look for code to inline from other translation units, but they just compile separate translation units into separate object files and only the linker would see the program in its entirety.

Back in times the solution for this would be to define a function in a header file with static (note it is a definition in a header file!), and hope that the compiler would be smart enough to inline the function. But a stupid compiler would generate a separate static function in each translation unit, and not inline anything, leading to both bad performance and wasted memory.

Now with inline and extern inline it means that a function defined as inline foo is supposed to be the same function throughout the program - you can take the function pointer of it in any translation unit and you will get the same function pointer.

Anywhere you see inline void foo(int bar) { ... } it is equally a function definition. But only in one translation unit in the entire program would there be extern inline void foo(int bar); that would cause the function with external linkage to appear in that file. This has a nice property in that it makes legacy tool chains (linkers etc) be able to completely ignore the inline keyword behaviour, they just see that there is one symbol foo for a function in that one object file.

Finally, you're not required to have the same function definition as the externally defined one - it can be a different one - just do not include the inline function definition from the header but define a completely different one, for example

inline int foo(void) {
    puts("Hello from an inlined function");
}

extern inline int foo(void) {
    puts("Hello from an external function using a completely different algorithm"
         " here that results in more code bloat but offsets the fact that the" 
         " function call to this definition was not inlined");
}

But it is nice that the C allows you to have the same definition without repeating yourself!

0

It might be clearer to say the extern declaration triggers generation of an external definition of the function rather than that it causes code to be generated.

As long as all of the declarations of a function in a translation unit are inline without extern, the compiler just provides inline implementations, per C 2018 6.7.4 7:

… If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function,…

So, when you add an extern declaration, the condition in that rule is no longer satisfied—it is no longer true that there are only inline declarations without extern. That cues the compiler to include an external non-inline implementation in the code it generates.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Seems like this could have been designed in a much better way. – Josh Jun 16 '20 at 01:50
  • @Josh: Most languages are not designed; they evolve in a series of changes. Most individual changes may be designed, but they are shaped and constrained by the past. – Eric Postpischil Jun 16 '20 at 01:59
  • 1
    @josh / eric: that's true, but in this case I'm not so sure it applies. The first popular implementation of `inline`, in a well known open source compiler, appeared to be more intuitive but the result was not so usable. The current solution is pretty well thought-out, IMHO, and very easy to use. In particular, it does not require the use of preprocessor macros nor duplicated code in the most common use cases. – rici Jun 16 '20 at 03:25