Qoobee
Qoobee

Reputation: 312

C99 referring to inline function: undefined reference to XXX and why should I put it to header?

Does gcc completely conform to the inline model specified in C99 standard?

I've browsed some info about this problem. But I can't understand why the inline func must be specified with "extern" or "static".

In .c file, calling an inline function defined in the same translation unit causes an error. What's the reason of compiler behaviour?

I found a post Is “inline” without “static” or “extern” ever useful in C99?

What does this mean?

If a call to some function func with external linkage occurs where an inline definition is visible, the behavior is the same as if the call were made to another function, say __func, with internal linkage.

Upvotes: 9

Views: 12588

Answers (4)

alecov
alecov

Reputation: 5171

C99's inline is not what most people expect it to be.

An inline func() in C99 only means the following: this is a definition for func you might use. If you don't use this definition, there is some other definition somewhere else. Raw inline functions never emit standalone symbols; whereas extern inline (or a declaration mentioning extern or not mentioning inline) always emit standalone symbols.

In other words, inline func() is barely useful in its raw form: if the compiler does not inline every func call in the same TU, then the compilation fails, because func is not really emitted. It is completely different from C++'s inline, which does emit a standalone func symbol if some call cannot be inlined.

This is a great reference on the inline semantics in C99 and GNU: https://www.greenend.org.uk/rjk/tech/inline.html. The four mentioned alternatives are the only alternatives that work well under GNU C.

A possible fifth, even better alternative, would be to reproduce C++'s inline symbol emission semantics into C, by making the symbol weak:

extern inline __attribute__((__weak__)) void f(void) {...}

This does work in Clang, but not in GCC (which is a very sad situation, because it is extremely useful). This makes any emitted symbol weak, which allows linking to proceed exactly as in C++'s case (which also does emit weak symbols).

The alternative in GCC is to use #pragma weak:

extern inline void f(void) {...}
#pragma weak f

which does require typing the function name twice, hence not possible to embed it in a neat PROPER_INLINE macro.

Upvotes: 0

user2074102
user2074102

Reputation:

You have to think about how code gets linked. First the source code is compiled to object files. These object files just contain the binary code of each function which are found by indexing the name of the function (or the mangled name in c++). The object files contain NO information about whether the function is to be inlined or not. So this information must be put into the header file which is used in combination with the object file during the linking process. By using static in front of inline in your .c file, you are making that function visible to any other function that uses that static inline function PRIOR to the compiling process. But once these functions are compiled into an object file, they cannot 'inlined' with other functions from other object files.

So by just including the inline keyword in your header definitions (.h file) instead of your source file (.c), you can 'inline' functions from one object file inside other functions from another object file in the linking process.

Upvotes: -1

Sergey L.
Sergey L.

Reputation: 22562

The inline semantic in C99 is a little bit confusing I have to admit. The inline quantifier allows you to define alternative definitions of a function.

If a function is defined everywhere as just inline in both declarations and definition then this definition is valid only in the local translation unit. In the C99 standard this definition is very vague, but in practice most compilers implement this in a similar sense to static inline. Essentially just inline overwrites any other function with the same name in any other linking unit. Thus if you declare a function as just inline in a header the compiler will expect to find a definition of it in the same compilation unit and will give you an error later if it doesn't.

Now if a function is to be both inlineable and available in other translation units then it needs to be defined as extern in the header declaration. Then the compiler won't look for it just in the current compilation unit.

static inline is by far the most portable definition at the moment and is constrained to the current translation unit. This is often found in headers together with the actual function definition.

Upvotes: 12

Jens Gustedt
Jens Gustedt

Reputation: 78973

inline function belong in the header, such that all compilation units see the code.

If the code can't be inlined for whatever reason, the final executable has to have one version of the function to which it may link. This you'd have to "instantiate" in just one compilation unit (.c file) with something like

extern inline void toto(int bla);

which forces a symbol to be included in that unit.

You may find more about that here

Upvotes: 10

Related Questions