Should One Never Use Static Inline Function

Should one never use static inline function?

Your analysis is correct, but doesn't necessarily imply uselessness. Even if most compilers do automatically inline functions (reason #1), it's best to declare inline just to describe intent.

Disregarding interaction with inline, static functions should be used sparingly. The static modifier at namespace scope was formerly deprecated in favor of unnamed namespaces (C++03 §D.2). For some obscure reason that I can't recall it was removed from deprecation in C++11 but you should seldom need it.

So, Practically marking a function static and inline both has no use at all. Either it should be static(not most preferred) or inline(most preferred),

There's no notion of preference. static implies that different functions with the same signature may exist in different .cpp files (translation units). inline without static means that it's OK for different translation units to define the same function with identical definitions.

What is preferred is to use an unnamed namespace instead of static:

namespace {
inline void better(); // give the function a unique name
}

static inline void worse(); // kludge the linker to allowing duplicates

static inline vs inline static

From the C standard (6.7 Declarations)

declaration:
declaration-specifiers init-declarator-listopt ;
static_assert-declaration

declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
alignment-specifier declaration-specifiersopt

It means that you may specify declaration specifiers in any order.

So for example all shown below function declarations declare the same one function.

#include <stdio.h>

static inline int getAreaIndex( void );
inline static int getAreaIndex( void );
int static inline getAreaIndex( void );
static int inline getAreaIndex( void );
inline int static getAreaIndex( void )
{
return 0;
}

int main(void)
{
return 0;
}

As for the inline function specifier then according to the C Standard (6.7.4 Function specifiers)

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.

and there is a footnote

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

Pay attention to that you should specify as the function parameter void. Otherwise the compiler will decide that the number and types of arguments are deduced from a function call.

When to use static inline instead of regular functions

Inlining is done for optimization. However, a little known fact is that inline can also hurt performance: Your CPU has an instruction cache with a fixed size, and inlining has the downside of replicating the function at several places, which makes the instruction cache less efficient.

So, from a performance point of view, it's generally not advisable to declare functions inline unless they are so short that their call is more expensive than their execution.

To put this in relation: a function call takes somewhere between 10 to 30 cycles of CPU time (depending on the amount of arguments). Arithmetic operations generally take a single cycle, however, memory loads from first level cache takes something like three to four cycles. So, if your function is more complex than a simple sequence of at most three memory accesses and some arithmetic, there is little point in inlining it.

I usually take this approach:

  • If a function is as simple as incrementing a single counter, and if it is used all over the place, I inline it. Examples of this are rare, but one valid case is reference counting.

  • If a function is used only within a single file, I declare it as static, not inline. This has the effect that the compiler can see when such a function is used precisely one time. And if it sees that, it will very likely inline it, no matter how complex it is, since it can prove that there is no downside of inlining.

  • All other functions are neither static nor inline.


The example in your question is a borderline example: It contains a function call, thus it seems to be too complex for inlining at first sight.

However, the memcpy() function is special: it is seen more as a part of the language than as a library function. Most compilers will inline it, and optimize it heavily when the size is a small compile time constant, which is the case in the code in question.

With that optimization, the function is indeed reduced to a short, simple sequence. I cannot say whether it touches a lot of memory because I don't know the structure that is copied. If that structure is small, adding the inline keyword seems to be a good idea in this case.

When to use the inline function and when not to use it?

Avoiding the cost of a function call is only half the story.

do:

  • use inline instead of #define
  • very small functions are good candidates for inline: faster code and smaller executables (more chances to stay in the code cache)
  • the function is small and called very often

don't:

  • large functions: leads to larger executables, which significantly impairs performance regardless of the faster execution that results from the calling overhead
  • inline functions that are I/O bound
  • the function is seldom used
  • constructors and destructors: even when empty, the compiler generates code for them
  • breaking binary compatibility when developing libraries:

    • inline an existing function
    • change an inline function or make an inline function non-inline: prior version of the library call the old implementation

when developing a library, in order to make a class extensible in the future you should:

  • add non-inline virtual destructor even if the body is empty
  • make all constructors non-inline
  • write non-inline implementations of the copy constructor and assignment operator unless the class cannot be copied by value

Remember that the inline keyword is a hint to the compiler: the compiler may decide not to inline a function and it can decide to inline functions that were not marked inline in the first place. I generally avoid marking function inline (apart maybe when writing very very small functions).

About performance, the wise approach is (as always) to profile the application, then eventually inline a set of functions representing a bottleneck.

References:

  • To Inline or Not To Inline
  • [9] Inline functions
  • Policies/Binary Compatibility Issues With C++
  • GotW #33: Inline
  • Inline Redux
  • Effective C++ - Item 33: Use inlining judiciously

EDIT: Bjarne Stroustrup, The C++ Programming Language:

A function can be defined to be inline. For example:

inline int fac(int n)
{
return (n < 2) ? 1 : n * fac(n-1);
}

The inline specifier is a hint to the compiler that it should attempt to generate code for a call of fac() inline rather than laying down the code for the function once and then calling through the usual function call mechanism. A clever compiler can generate the constant 720 for a call fac(6). The possibility of mutually recursive inline functions, inline functions that recurse or not depending on input, etc., makes it impossible to guarantee that every call of an inline function is actually inlined. The degree of cleverness of a compiler cannot be legislated, so one compiler might generate 720, another 6 * fac(5), and yet another an un-inlined call fac(6).

To make inlining possible in the absence of unusually clever compilation and linking facilities, the definition–and not just the declaration–of an inline function must be in scope (§9.2). An inline especifier does not affect the semantics of a function. In particular, an inline function still has a unique address and so has static variables (§7.1.2) of an inline function.

EDIT2: ISO-IEC 14882-1998, 7.1.2 Function specifiers

A function declaration (8.3.5, 9.3, 11.4) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.

Usage of static inline to functions which calls other larger functions in C

It does not matter. The function total will not be probably inlined (normal function call will be emitted). Function res probably will be inlined.

Why probably. Because the inline keyword is only a suggestion. Functions without inline may be inlined as well. The compiler may inline the total function as well if decides that on a certain level of optimization it will result in the best code generation.

Many compilers have special extensions which give you control over inlining. for example:

gcc has __attribute__((noinline)) and __attribute__((always_inline)).

iar #pragma inline=never and pragma inline=force

Should I define static inline methods in header file?

How to add a function definition in header file?

This can be achieved in 3 possible ways:

  1. Marking the function inline or
  2. Making the function static or
  3. Putting the functions in anonymous namespace.

What is the correct way to do so?

#1 i.e: Marking the function inline is the correct way to this without breaking the One Definition Rule.

What is wrong with the other two appraoches?

In both #2 & #3 each Translation Unit will contain it's own version of the function, and the program will contain several different versions of the function thus leading to a increase in size of the generated binary.

i.e: For a static function fun(), &fun will be different in each translation unit, and the program will contain N different versions of the function.

Also, If the function contains static local variables then there will be N different static local variables, one for each function instance.

How the first approach avoids this problem?

An inline function has external linkage.

When you mark a function inline the function will have the same address in all translation units. Also, Static locals and string literals defined within the body of an inline function are treated as the same object across translation units.

In short, a inline function will have the same address across all translation units.

What is the deal with static inline function definitions in header?

The static keyword forces the function to have a internal linkage.

Each instance of function defined as inline is treated as a separate function and each instance has its own copy of static locals and string literals. Thus, this would be similar to #2.

Note:
The standard mandates that all definitions of inline function in an user program You must have the exact same definition in all translation units in which the function is used or called.


Relevant Standerdese references:

C++03 Standard

3.2 One definition rule:
Para 3:

Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is used.

7.1.2 Function specifiers
Para 4:

An inline function shall be defined in every translation unit in which it is used and shall have exactly the same definition in every case (3.2). [Note: a call to the inline function may be encountered before its definition appears in the translation unit. ] If a function with external linkage is declared inline in one translation unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required. An inline function with external linkage shall have the same address in all translation units. A static local variable in anextern inline function always refers to the same object. A string literal in an extern inline function is the same object in different translation units.



Related Topics



Leave a reply



Submit