liveBook · Manning

Inline function

As explained in Modern C

inline is a C function specifier that permits a function definition to be suitable for direct integration into callers without changing its semantics.

A square with one argument evaluation

Consider `inline unsigned square_unsigned(unsigned x) { return x*x; }`. If `count()` increments a counter, `square_unsigned(count())` calls `count()` once. By contrast, `#define square_macro(X) (X*X)` expands `square_macro(count())` to `count()*count()`, calling it twice. When the argument count and type are known, prefer the function’s type-safe interface. section 16.0

An inline definition makes a function available for possible integration into its callers. Instead of performing a call, the compiler may use the function’s code at the call site, avoiding call overhead. Seeing that code in context may also expose dead branches or repeated computations. TAKEAWAY: `inline` makes an optimization possible; it does not promise that every call will be inlined. section 15.1

Keep visibility and linkage separate:

  • A compiler traditionally needs the definition, not merely a declaration, to inline a function. A header can make that definition visible to each translation unit that includes it. section 15.1
  • A header containing an inline definition can be paired with a non-inline declaration in exactly one translation unit to instantiate the function there. section 15.1
  • Placing a `static` definition in a header is another way to expose code, but a function not actually inlined can then have a separate instance in every translation unit. section 15.1
 1   // Inline definition in a header file.
 2   // Function argument names and local variables are visible
 3   // to the preprocessor and must be handled with care.
 4   inline 
 5   toto* toto_init(toto* toto_x) {
 6     if (toto_x) {
 7       *toto_x = (toto){ 0 };
 8     }
 9     return  toto_x;
10   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":1,\"ch\":1},{\"line\":1,\"ch\":2}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":1}],[{\"line\":2,\"ch\":1},{\"line\":2,\"ch\":2}],[{\"line\":3,\"ch\":1},{\"line\":3,\"ch\":2}],[{\"line\":4,\"ch\":1},{\"line\":4,\"ch\":2}],[{\"line\":4,\"ch\":5},{\"line\":4,\"ch\":11}],[{\"line\":5,\"ch\":1},{\"line\":5,\"ch\":2}],[{\"line\":6,\"ch\":1},{\"line\":6,\"ch\":2}],[{\"line\":6,\"ch\":7},{\"line\":6,\"ch\":9}],[{\"line\":7,\"ch\":1},{\"line\":7,\"ch\":2}],[{\"line\":8,\"ch\":1},{\"line\":8,\"ch\":2}],[{\"line\":9,\"ch\":1},{\"line\":9,\"ch\":2}],[{\"line\":9,\"ch\":7},{\"line\":9,\"ch\":13}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":2}]]"}
!@%STYLE%@!

Inspect an inline definition intended for a header. Its parameter and local names are visible to the preprocessor, so name them with care. section 15.1

1   #include "toto.h"
2
3   // Instantiate in exactly one TU.
4   // The parameter name is omitted to avoid macro replacement.
5   toto* toto_init(toto*);


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":1}],[{\"line\":0,\"ch\":4},{\"line\":0,\"ch\":12}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":1}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":1}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":1}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":1}]]"}
!@%STYLE%@!

Compare the separate declaration used to instantiate that function in exactly one translation unit. section 15.1

Inline functions can also supply the typed operations behind a type-generic macro: `_Generic` selects among separate floating-point minimum functions. Use such combinations when a macro provides something a fixed-argument function cannot. Do not trade correctness or safety for an assumed performance gain; inline is particularly suited to small, pure functions. section 16.6 section 15.4

How Modern C covers it

How deep it goes
Explains call-site optimization and header layout, while making actual inlining a compiler choice rather than a guarantee.
Examples
Contrasts squaring a counter through a macro and an inline function, then shows a header definition with a separate declaration.
What it assumes
Assumes familiarity with function calls and headers; introduces inlining through call overhead and definition visibility.
What you can do after
Build it from scratch: define a typed inline helper in a header and arrange its instantiation in one translation unit.
How it connects
Connects inline functions to translation units, header files, static functions, function-like macros, and _Generic.

Also explained in

Compare how 4 books explain inline function →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.