What Does Extern Inline Do

What's the difference between static inline, extern inline and a normal inline function?

A function definition with static inline defines an inline function with internal linkage. Such function works "as expected" from the "usual" properties of these qualifiers: static gives it internal linkage and inline makes it inline. So, this function is "local" to a translation unit and inline in it.

A function definition with just inline defines an inline function with external linkage. However, such definition is referred to as inline definition and it does not work as external definition for that function. That means that even though this function has external linkage, it will be seen as undefined from other translation units, unless you provide a separate external definition for it somewhere.

A function definition with extern inline defines an inline function with external linkage and at the same time this definition serves as external definition for this function. It is possible to call such function from other translation units.

The last two paragraphs mean that you have a choice of providing a single extern inline definition for an inline function with external linkage, or providing two separate definitions for it: one inline and other extern. In the latter case, when you call the function the compiler is allowed to chose either of the two definitions.

What happens with an extern inline function?

Having added the inline to the function definition in the .c file is just superfluous.

  • Your compilation unit of the .c file sees an extern declaration (without inline) and an inline definition. Thus it emits the symbol for the function in the object file.

  • All other compilation units only see an extern declaration, and so they can use the function without problems, if you link your final executable with the other .o file.

In fact, you just have it the wrong way around. This feature is meant to be used that you have the inline defintion in the .h file, visible to everybody. This definition of the function only acts as a declaration of the symbol, just as extern would, but doesn't define it.

An extern declaration in just one .c file (compilation unit) then ensures such that the symbol is defined, there.

The terminology is a bit confusing, the inline definition acting as declaration of the symbol, and the extern declaration acting as definition of it

static and extern inline functions in C

Your code is incorrect because you cannot declare a function with extern (which is default) and afterwards provide a static definition. The fact that it compiles at all does not indicate anything useful.

From n1548 §6.2.2:

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

So, you get something like this in file1.c:

// Has external linkage (which is the default!)
extern inline void fun1(void);

// This would also have external linkage.
inline void fun1(void);

// This has static linkage.
static inline void fun1(void) {
...
}

(Note: "external linkage" is the default but extern inline actually means something special, it's different from inline.)

Bam! Undefined behavior. The compiler may not even give you an error message, although some compilers appear to give error messages for this.


error: static declaration of 'func' follows non-static declaration

This error actually has nothing to do with the fact that the function is inline. It is an error with or without inline.

What about those questions?

static inline functions are visible only to translation unit where it is defined.

This is true of all static functions. They have "internal linkage" so you can have static void func(void); in one file and a completely different static int func(char *p); in a different file. The inline makes no difference here.

extern inline functions can be access in more than one translation units.

Yes, which is why you shouldn't put them in header files. If you put them in header files, you will get multiple different definitions of the same function, which can all be accessed from different translation units. This is an error. Instead, put the extern inline in source files, but it only needs to be a declaration, not a definition.

Better to define inline functions in header files

There is no real point to defining an inline function anywhere else. If your function is only used in one file just mark it static and the compiler will decide how to call the function.

There is no difference between static and static inline function definitions.

Yes, there is no difference.

Well, technically, no, there is a difference because the compiler is allowed to treat static inline functions differently from just static functions. However, modern compilers tend to decide to inline functions using their own set of rules, and whether a function is inline doesn't affect that process very much.

Well, practically there is one other difference. A static inline function definition won't generate a warning in GCC if it's not used, but a static function will. This is so you can put a static inline function in a header file. This is an alternative to putting inline in the header file, which requires you to have an extern inline for that function somewhere in your program. However, if the compiler decides that it would rather not inline your static inline function, either because it think's that inlining is worse or because inlining is impossible, then it will have to make a separate copy of that function in each file it's used in.

So, how do you do it correctly?

Never declare a function static if it has a previous, non-static declaration. This is an error, even if it compiles.

Don't declare an inline extern function in a header file. This creates an "external definition" for the function, and you can only have one of those in your entire program.

Don't declare inline functions in header files without defining them. There is no point.

Here is how you would want to do this:

In mylib.h:

// Provide "inline definition" of the function.
inline int times_two(int x) {
return x * 2;
}

In mylib.c:

#include "mylib.h"

// Provide "external definition" of the function.
extern inline int times_two(int x);

This is the standard way to do things since C99. The compiler should be free to use the internal definition or the external definition, whichever one it thinks is better. If you don't have an external definition or you have more than one, you may get a linking error, just like with regular functions.

C++ has its own completely different rules for inline functions.

Understanding this extern inline call in C99

C99 inline functions are not like C++ inline functions.

They aren't merged. You're expected to provide an extern definition if you don't make it static.

The way you do that for an inline function f is by providing an extern declaration (e.g., int f(void);, extern int f(void);, or extern inline int f(void);) in a translation unit where an inline definition for f (e.g., inline f(void){ return 42; }) is also provided.

The order is not important.

inline int f(void) { return 42; }
int f(void);

provides an external definition just like

int f(void);
inline int f(void) { return 42; }

does.

A translation unit with just inline declarations/definitions without an extern declaration will not provide an extern definition:

 inline int f(void); 
//^if an inline decl is present a definition MUST follow or else you get a diagnostic
inline int f(void) { return 42; }
inline int f(void); //a pointless but legal redeclaration

Usually you'll have an inline definition in a header like in your example, and then to instantiate it, you'll include the header and provide an extern declaration. Including extern or extern inline in the declaration is technically unnecessary but it makes it clear that that declaration's goal is to instantiate an extern definition of an inline function.

More info at 6.7.4p7. (I find this particular part of the C standard somewhat cryptic but usage examples are provided.)

Differentiate extern inline and inline in C

With respect to the first, "inline function" example, you say (highlighting added to function names),

Since fun1 is a inline definition in temp2.c, it will be seen as
undefined from temp1.c. So external declaration in temp1.c made
temp1.c to access fun1 from temp2.c.

Your explanation is incorrect, or at least misworded. In this example, your temp2.c does not provide an external definition of function fun1(). The declaration in temp1.c says that there is an external definition somewhere, but temp2.c is not that place. There needs to be an external definition provided by some other translation unit. Function fun1 in temp2.c is an inline function because it is declared with the inline keyword (that's all it means to be an "inline function"), but the definition of fun1 in that file is not an inline definition, because temp2.c contains another declaration of its identifier that does not include the inline keyword. Since fun1 is declared with (implicitly) external linkage, that is an external definition of fun1. Anyone can call it. To get an inline definition of a function, every declaration of its identifier in the TU must include the inline keyword and must omit the extern keyword.

Standard C does require the function to be declared in temp1.c if it is to be called from that TU, but nothing you put in that file could enable code within to access an inline definition of fun1 from a different TU. Only external definitions are accessible across TUs -- that's what being an external definition means.

Note: The original (now stricken-out) text of this part of this answer supposed that temp2.c indeed did provide an inline definition of function fun1, because I overlooked the flaw(?) in the declarations.

I am confused as in the quotes it
is saying "separate external definition" instead of external
declaration.

A function definition comprises a declaration of that function, but not every function declaration is part of a definition. We must be careful with our wording here. There is no meaningful sense of an "external function declaration" in C, in that no declaration has a scope wider than its translation unit.

But one can, and often does, have (local) declarations of functions with external linkage. This is the default, applicable to all function declarations that do not include the keyword static. That default can be made explicit by use of the extern keyword, and that happens to have additional significance for declarations of inline functions.

An external function definition, on the other hand, is one that can be accessed by name from another translation unit. An inline definition explicitly is not an external definition. Thus, your first example declares that there is a function fun1 with external linkage, but does not if all the declarations of that identifier carried the inline keyword and not extern then it would not provide a corresponding external definition of that function. If that function is were called, even from a source file that provides an inline definition, then the absence of an external definition is would be an error.


With respect to the second, "extern inline function" example, you say (highlighting added to function names),

Since fun1 is extern inline function, it can be called from temp1.c.

Let's separate out the properties here.

  • fun1 is (still) declared as a function with external linkage.
  • The presence of the inline specifier in the declaration that is part of its definition makes it an inline function.
  • The presence of the explicit extern specifier on a declaration of that function in the same translation unit as a definition makes the definition in that TU an external one.

It is the fact that the definition in temp2.c is an external one that makes it callable from temp1.c.

The only difference what I observed is, no need of explicit
declaration of the extern inline function where it is defined.

There is no need for a forward declaration of fun1() in the first example, either. There would be a need for a forward declaration in both cases if temp2.c contained a call to fun1 prior to that function's definition. There is no difference here.


Update:

You are more or less right. Your two alternatives are different ways to declare an an inline function with external linkage and to provide an external definition for it. Instead, the thing you should be comparing to, and to which the original text of this answer was erroneously addressed, would be this:

#include <stdint.h>

inline int32_t fun1(void);

inline int32_t fun1(void)
{
return 0;
}

or, equivalently, this:

#include <stdint.h>

inline int32_t fun1(void)
{
return 0;
}

In those cases, the provided definition of fun1 is an inline definition, accessible only from the translation unit of temp2.c. Of course, that's not useful unless there is code in that TU that actually calls the function.


Is it the only difference ? else what are the other major difference
and the scope of inline and extern inline functions ?

You are doing yourself a disservice by attempting to set up "inline" and "extern inline" as classes of functions. There are inline functions and non-inline functions. There are function identifiers with internal linkage and those with external linkage. There are inline function definitions, internal ones, and external ones, and appearance of a function declaration in a TU does not necessarily require a definition in the same TU. These combinations (and only these) of those properties are possible:

  • function identifier is declared with external linkage, function is not an inline function, and an external definition of the function appears in the TU
  • function identifier is declared with external linkage, function is not an inline function, and no definition of the function appears in the TU with the declaration. If the function identifier is referenced in the TU then an external definition appears in a different TU.
  • function identifier is declared with external linkage, function is an inline function, and an inline definition of the function appears in the TU. If the function identifier is referenced in the TU then an external definition appears in a different TU.
  • function identifier is declared with external linkage, explicitly, function is an inline function, and an external definition of the function appears in the TU
  • function identifier is declared with internal linkage, the function is not an inline function, an internal definition of the function appears in the TU
  • function identifier is declared with internal linkage, the function is not an inline function, an no definition of the function appears in the TU. The function identifier is never referenced in that TU.
  • function identifier is declared with internal linkage, the function is an inline function, an inline definition of the function appears in the TU

A function identifier declared with external linkage in a given TU refers refers to an external function definition, which may appear in a different TU.

A function identifier declared with internal linkage in a given TU refers refers to an internal or inline function definition in the same TU.

An inline function declaration may have either external or internal linkage, in either case, an inline definition of that function must appear in the same TU. If the function identifier has external linkage (in that TU) and an inline function definition then it is left to the discretion of the implementation whether and where the inline definition or the (required) external definition elsewhere is used within that TU.


Update:

Upon reflection, your characterization of functions themselves as "inline functions" and "extern inline functions" seems to reflect the idea that inline character of a function is globally associated with the function's identifier (e.g. fun1), at least for identifiers with external linkage. This is not the case, as I hope my rather lengthy discourse has conveyed.

Inline character of a function identifier is a per-TU property, and inline character of a function definition is a separate, per-definition property. If in any TU you declare a given function to be an inline function, then you must provide a definition of that function in that TU. An external definition of a function from a different TU does not satisfy that requirement, even if the function is declared to be an inline function in the TU in which the definition appears.

Is an external linkage inline function really inline?

In the question you try things in the compiler to try and deduce the language rules. This is generally a bad idea, because (a) in many situations the effect of breaking the rules is hard to observe, and (b) the compiler might be bugged. Instead, the Standard is an authoritative source for what the language rules are, so the question should be answered by referring to the Standard.


Moving on: your code contains a constraint violation of C11 6.7.4/3, which you quoted in your question. The effect of a constraint violation is that the compiler must issue a diagnostic, which it did.

Then you ask about some modification, I assume you mean the following code:

static int n = 5;
void inline foo() { n = 66; }
void foo();
int main() { return 0; }

As covered by the first sentence you quoted (from 6.7.4/7), the definition of foo() is not an inline definition, because it is not true that all of the file-scope declarations in the TU include the inline specifier without extern. (That sentence is intended to deny the antecedent).

Since it is not an inline definition, there is no problem with n = 66 and the code is correct.

What the standard is not saying, or at least I cannot see it, is whether an inline function that provides an external definition stops being an inline function, or not

An inline function definition is never an external definition. This is clearly stated in 6.7.4/7 "An inline definition does not provide an external definition for the function".

Maybe your confusion arises from conflating the concepts "inline function definition" and "function definition with the inline specifier".

another question arises: why an extern inline function is a useless thing?

If you mean the keywords extern inline that is another topic that was not touched on by this question, see here. Inline functions with external linkage are certainly not useless .



Related Topics



Leave a reply



Submit