What is the use of the `inline` keyword in C?

Note: when I talk about .c files and .h files in this answer, I assume you have laid out your code correctly, i.e. .c files only include .h files. The distinction is that a .h file may be included in multiple translation units.

static inline void f(void) {} has no practical difference with static void f(void) {}.

In ISO C, this is correct. They are identical in behaviour (assuming you don't re-declare them differently in the same TU of course!) the only practical effect may be to cause the compiler to optimize differently.

inline void f(void) {} in C doesn't work as the C++ way. How does it work in C? What actually does extern inline void f(void); do?

This is explained by this answer and also this thread.

In ISO C and C++, you can freely use inline void f(void) {} in header files -- although for different reasons!

In ISO C, it does not provide an external definition at all. In ISO C++ it does provide an external definition; however C++ has an additional rule (which C doesn't), that if there are multiple external definitions of an inline function, then the compiler sorts it out and picks one of them.

extern inline void f(void); in a .c file in ISO C is meant to be paired with the use of inline void f(void) {} in header files. It causes the external definition of the function to be emitted in that translation unit. If you don't do this then there is no external definition, and so you may get a link error (it is unspecified whether any particular call of f links to the external definition or not).

In other words, in ISO C you can manually select where the external definition goes; or suppress external definition entirely by using static inline everywhere; but in ISO C++ the compiler chooses if and where an external definition would go.

In GNU C, things are different (more on this below).

To complicate things further, GNU C++ allows you to write static inline an extern inline in C++ code... I wouldn't like to guess on what that does exactly

I never really found a use of the inline keyword in my C programs, and when I see this keyword in other people's code, it's almost always static inline

Many coders don't know what they're doing and just put together something that appears to work. Another factor here is that the code you're looking at might have been written for GNU C, not ISO C.

In GNU C, plain inline behaves differently to ISO C. It actually emits an externally visible definition, so having a .h file with a plain inline function included from two translation units causes undefined behaviour.

So if the coder wants to supply the inline optimization hint in GNU C, then static inline is required. Since static inline works in both ISO C and GNU C, it's natural that people ended up settling for that and seeing that it appeared to work without giving errors.

, in which I see no difference with just static.

The difference is just in the intent to provide a speed-over-size optimization hint to the compiler. With modern compilers this is superfluous.


From 6.7.4 Function specifiers in C11 specs

6 A function declared with an inline function specifier is an inline function. Making a function an inline function suggests that calls to the function be as fast as possible.138)The extent to which such suggestions are effective is implementation-defined.139)

138) By using, for example, an alternative to the usual function call mechanism, such as inline substitution. Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.

139) For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration.

It suggests compiler that this function is widely used and requests to prefer speed in invocation of this function. But with modern intelligent compiler this may be more or less irrelevant as compilers can decide whether a function should be inlined and may ignore the inline request from users, because modern compilers can very effectively decide about how to invoke the functions.

static inline void f(void) {} has no practical difference with static void f(void) {}.

So yes with modern compilers most of the time none. With any compilers there are no practical / observable output differences.

inline void f(void) {} in C doesn't work as the C++ way. How does it work in C?

A function that is inline anywhere must be inline everywhere in C++ and linker does not complain multiple definition error (definition must be same).

What actually does extern inline void f(void); do?

This will provide external linkage to f. Because the f may be present in other compilation unit, a compiler may choose different call mechanism to speed up the calls or may ignore the inline completely.


A C code can be optimized in two ways: For Code size and for Execution Time.

inline functions:

gcc.gnu.org says,

By declaring a function inline, you can direct GCC to make calls to that function faster. One way GCC can achieve this is to integrate that function's code into the code for its callers. This makes execution faster by eliminating the function-call overhead; in addition, if any of the actual argument values are constant, their known values may permit simplifications at compile time so that not all of the inline function's code needs to be included. The effect on code size is less predictable; object code may be larger or smaller with function inlining, depending on the particular case.

So, it tells the compiler to build the function into the code where it is used with the intention of improving execution time.

If you declare Small functions like setting/clearing a flag or some bit toggle which are performed repeatedly, inline, it can make a big performance difference with respect to time, but at the cost of code size.


non-static inline and Static inline

Again referring to gcc.gnu.org,

When an inline function is not static, then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-static inline function is always compiled on its own in the usual fashion.


extern inline?

Again, gcc.gnu.org, says it all:

If you specify both inline and extern in the function definition, then the definition is used only for inlining. In no case is the function compiled on its own, not even if you refer to its address explicitly. Such an address becomes an external reference, as if you had only declared the function, and had not defined it.

This combination of inline and extern has almost the effect of a macro. The way to use it is to put a function definition in a header file with these keywords, and put another copy of the definition (lacking inline and extern) in a library file. The definition in the header file causes most calls to the function to be inlined. If any uses of the function remain, they refer to the single copy in the library.


To sum it up:

  1. For inline void f(void){}, inline definition is only valid in the current translation unit.
  2. For static inline void f(void) {} Since the storage class is static, the identifier has internal linkage and the inline definition is invisible in other translation units.
  3. For extern inline void f(void); Since the storage class is extern, the identifier has external linkage and the inline definition also provides the external definition.

Tags:

C

C99

Inline