39

The way I think of inline in C++ is for linkage/scoping. I put it in the same basket with extern and static for global objects.

Typically for a function implemented in a header file, my go-to solution would be to make it static:

// In Foo.h
static void foo()
{
    // Do stuff...
}

However, I believe this is also valid and does not seem to violate ODR:

// In Foo.h
inline void foo()
{
    // Do stuff...
}

What are the semantic differences between the two? Also I'm not exactly sure what areas of the C++ standard would explain exact differences, or if it's just undefined and differences lie with the implementation.

void.pointer
  • 24,859
  • 31
  • 132
  • 243
  • 1
    Please see this post regarding inline, static, and static inline functions. http://stackoverflow.com/a/12836392/2296458 – Cory Kramer Feb 28 '14 at 18:25
  • 1
    It's very easy to get an ODR violation when you define functions with internal linkage in a header file. – Simple Feb 28 '14 at 18:30
  • 1
    @Cyber I did review it and I don't find it very helpful, especially considering how I'm not specifically concerned with `static inline` used together. Just the semantic differences between the two as it applies to my contrived example. Unfortunately the answers there did not satisfy the unknowns for me. – void.pointer Feb 28 '14 at 20:30

5 Answers5

56

inline conveys exactly what you want: "please suppress the ODR (One Definition Rule) for this function, so that each translation unit can (and must) supply its own copy of the function's definition".

The compiler will then either inline calls to the function, or merge together the function definitions from different TU's (so that the resulting function exists once in the executable).

static, on the other hand, tells the compiler to generate the function in every translation unit where it is defined, and just not share it. So you end up with an arbitrary number of technically separate functions existing in the resulting executable.

In a nutshell, if you use static, then taking the address of the function in different translation units will return different addresses (because you're telling the compiler to generate a function in each TU), but if you use inline, they'll show the same address (because you're defining one function, and just telling the compiler to merge the many definitions together).

marsh
  • 2,592
  • 5
  • 29
  • 53
jalf
  • 243,077
  • 51
  • 345
  • 550
  • 5
    What if you do `static inline`, then? – jrok Feb 28 '14 at 18:37
  • 2
    @jrok: `static inline` is the same as `static` semanitcally -- the only difference is the compiler hint which may have no effect. – Chris Dodd Feb 28 '14 at 18:38
  • 3
    @ChrisDodd Yes, and it's maybe worth mentioning? – jrok Feb 28 '14 at 18:40
  • 3
    Could you clarify "each translation unit can (and must) supply its own copy" and "so that the resulting function exists once in the executable"? It seems contradictory. – s.bandara Feb 28 '14 at 18:48
  • If `static` results in each TU having its own copy, the linker should eliminate duplicates as an optimization to reduce executable size, correct? The only concern is with function addressing and how the linker handles & detects that. Also in my example the inline function is *defined* in the header. How does the linker know which TU owns that one copy, per your definition? – void.pointer Feb 28 '14 at 20:28
  • @RobertDailey In the inline case, no TU owns the copy. Every TU which uses the function must bring along its own definition as well. Then the linker merges them all together into one. In the static case, the linker *might* be able to merge them, but don't rely on it (if there is a chance that the address of the function might be taken, the compiler almost certainly can't get away with merging them. Don't assume they'll be merged. If you want them merged, use the `inline` keyword. It does *exactly* what you need. :) – jalf Mar 01 '14 at 00:55
  • 1
    @s.bandara The compiler requires every TU that contains a call to the function, to also contain a definition of it. In other words, the function must exist in every TU (or at least in every TU that uses the function). But the linker is required to merge all these instances of the function back together, so the final executable will only have one instance of the function (at most. It may have zero, if *all* calls were inlined) – jalf Mar 01 '14 at 00:57
  • WRT "inline": Say that you define an inline function X in "global.h", and that it is never actually inlined anywhere. Suppose that "file1.cpp" is compiled with optimization enabled, but "file2.cpp" is compiled with optimizations disabled. The linker may choose either file1.o:X or file2.o:X. Worse you *promised* (ODR) that all instances of X() are identical, but due to difference in #defines, the X() in each *.o can be funtionally different as well. Compilers/Linkers don't usually detect this problem - it is left as an exercise for the programmer :-) – joeking Mar 04 '14 at 23:36
  • If the static function is a class method that is forward declared does it still create a new copy or does the address stay the same in each compilation unit? – marsh Aug 02 '17 at 15:47
  • Why would you want to have separate declarations of the same function using the `inline` keyword when you could just define the function once in a separate TU, and include its declaration in the global header file? – James Paul Turner Jul 23 '19 at 16:03
  • @marsh You can't have static linkage on a class method, because using the static keyword on a method gives you a static method with global linkage. There's just no way in the language to get static linkage on a method (and it is not clear what it would mean anyways). – Chris Dodd Mar 29 '23 at 10:04
13

The main difference is what happens with any static locals in the function -- if the function is static then each compilation unit will have its own copy of the static locals distinct from any other compilation unit. If the function is inline, there will only be one (set of) static local(s) shared by all compilation units.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
7

In many cases you will not notice a difference because compilers and linkers are pretty smart these days. However, an inline function must behave as-if it was a regular function. A static function in a header will get compiled into every source file which includes it - so there will be lots of copies of it.

Mostly, this doesn't matter much, but there are a few ways it does. An inline function has one address. Static functions will have a different address in each translation unit.

Static-local variables: WIth the inline, there will be a single copy of them. With static-functions, there will be a unique copy of each static-local variable for each translation unit that includes that function.

joeking
  • 2,006
  • 18
  • 29
0

Thinking about this question from the original intents of keywords inline and static may be more helpful and clear.

  1. inline functions

The original intent of keyword inline is to improve runtime performance, not for linkage/scoping as you said at the beginning. It is a hint that makes compiler attempt to generate code inline at the calling point rather than laying down the code once and calling it every time, which can avoid some overheads such as creating stack frame for the calls. In order to generate code inline, the function definition must be in scope, not just the declaration like ordinary functions. So, you should put the whole function definition in a header file foo.h, and #include "foo.h" when call it. These inline functions in different translation units must be identical token-by-token to obey ODR(One Definition Rule). And these all inline functions are just one single function, and so do static variables in this inline function.

  1. static functions

Keyword static can be used to make functions local to a translation unit, namely that it gives them internal linkage. So if you put the whole function definition of foo() into a header file foo.h and mark it as static, all translation units which #include "foo.h" will have a local function foo(). In other words, the functions foo() in different translation units are not one single function, and neither do the static variables in these static functions.

  1. static inline functions

So you can guess functioins marked by both static and inline. These are not the same functions in different translation units like static functions, but can give performance improvement by generate code inline.

-6

No one seems to be mentioning that in C++, a static function is one that is called directly, not on an instance of the class. In other words, there is no implicit "this" pointer. If function foo of class MyClass is static, you say:

MyClass::foo(); // calls it

and not: MyClass an_object = new MyClass(); an_object->foo();

Jonathan Starr
  • 236
  • 4
  • 15
  • 5
    Because that's completely unrelated. The static keyword, for a member function, makes it a static member function (what you describe). But for a non-member function, as in the question, the static keyword gives the function static linkage (it becomes invisible outside of current translation unit). – spectras Nov 05 '19 at 16:14