Functions declared as
inline are slightly more complex than might be expected. Douglas Walls has provided a chapter-and-verse write up. But the issue bears further explanation.
When a function is declared as
inline it's a hint to the compiler that the function could be inlined. It is not a command to the compiler that the function must be inlined. If the compiler chooses not to inline the function, then the function will be left with a function call that needs to be resolved, and at link time it will be necessary for a function definition to be provided. Consider this example:
inline void foo()
printf(" In foo\n");
The code provides an inline definition of foo(), so if the compiler chooses to inline the function it will use this definition. However, if it chooses not to inline the function, you will get a link time error when the linker is unable to find a suitable definition for the symbol
$ cc -o in in.c
Undefined first referenced
symbol in file
ld: fatal: symbol referencing errors. No output written to in
This can be worked around by adding either "static" or "extern" to the definition of the inline function.
If the function is declared to be a
static inline then, as before the compiler may choose to inline the function. In addition the compiler will emit a locally scoped version of the function in the object file. There can be one static version per object file, so you may end up with multiple definitions of the same function, so this can be very space inefficient. Since all the functions are locally scoped, there is are no multiple definitions.
Another approach is to declare the function as
extern inline. In this case the compiler may generate inline code, and will also generate a global instance of the function. Although multiple global instances of the function might be generated in all the object files, only one will be remain in the executable after linking. So declaring functions as
extern inline is more space efficient.
This behaviour is defined by the standard. However, gcc takes a different approach, which is to treat
inline functions by generating a global function and potentially inlining the code. Unfortunately this can cause multiply-defined symbol errors at link time, where the same
extern inline function is declared in multiple files. For example, in the following code both in.c and in2.c include in.h which contains the definition of
extern inline foo()....
$ gcc -o in in.c in2.c
ld: fatal: symbol 'foo' is multiply-defined:
The gcc behaviour for functions declared as
extern inline is also different. It does not emit an external definition for these functions, leading to unresolved symbol errors at link time.
For gcc, it is best to either declare the functions as
extern inline and, in additional module, provide a global definition of the function, or to declare the functions as
static inline and live with the multiple local symbol definitions that this produces.
So for convenience it is tempting to use
static inline for all compilers. This is a good work around (ignoring the issue of duplicate local copies of functions), except for an issue around unused code.
static tells the compiler to emit a locally-scoped version of the function. Solaris Studio emits that function even if the function does not get called within the module. If that function calls a non-existent function, then you may get a link time error. Suppose you have the following code:
static inline unused()
Compiling this we get the following error message:
$ cc -O i.c
"i.c", line 3: warning: no explicit type given
Undefined first referenced
symbol in file
Even though the function call exists in code that is not used, there is a link error for the undefined function
error_message(). The same error would occur if
extern inline was used as this would cause a global version of the function to be emitted. The problem would not occur if the function were just declared as
inline because in this case the compiler would not emit either a global or local version of the function. The same code compiles with gcc because the unused function is not generated.
So to summarise the options:
static inline, and ensure that there are no undefined functions, and that there are no functions that call undefined functions.
inlinefor Studio and
extern inlinefor gcc. Then provide a global version of the function in a separate file.