57

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.

3
  • 1
    Please see this post regarding inline, static, and static inline functions. stackoverflow.com/a/12836392/2296458 Commented Feb 28, 2014 at 18:25
  • 1
    It's very easy to get an ODR violation when you define functions with internal linkage in a header file. Commented Feb 28, 2014 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. Commented Feb 28, 2014 at 20:30

6 Answers 6

72

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).

Sign up to request clarification or add additional context in comments.

13 Comments

What if you do static inline, then?
@jrok: static inline is the same as static semanitcally -- the only difference is the compiler hint which may have no effect.
@ChrisDodd Yes, and it's maybe worth mentioning?
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 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)
|
16

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.

Comments

8

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.

Comments

4

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.

Comments

3

The top-rated answer above does a pretty good job addressing the question. But I was quite curious about the last paragraph:

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).

So, I wrote small programs for better understanding:

funcs.hpp:

#pragma once

#include <iostream>

static void staticFunc() {
    std::cout << "inside staticFunc" << std::endl;
}

inline void inlineFunc() {
    std::cout << "inside inlineFunc" << std::endl;
}

translation_unit_1.cpp:

#include "funcs.hpp"

void printFuncAddressesTu1() {
    std::cout << "Translation Unit 1 - Address of staticFunc: " << (void*)staticFunc << std::endl;
    std::cout << "Translation Unit 1 - Address of inlineFunc: " << (void*)inlineFunc << std::endl;
}

translation_unit_2.cpp:

#include "funcs.hpp"

void printFuncAddressesTu2() {
    std::cout << "Translation Unit 2 - Address of staticFunc: " << (void*)staticFunc << std::endl;
    std::cout << "Translation Unit 2 - Address of inlineFunc: " << (void*)inlineFunc << std::endl;
}

main.cpp:

#include <iostream>

// Declrations of functions in different translation units
void printFuncAddressesTu1();
void printFuncAddressesTu2();

int main() {
    printFuncAddressesTu1();
    printFuncAddressesTu2();

    return 0;
}

Upon running g++ main.cpp translation_unit_1.cpp translation_unit_2.cpp && ./a.out, it prints:

Translation Unit 1 - Address of staticFunc: 0x5586be0f9218
Translation Unit 1 - Address of inlineFunc: 0x5586be0f931a
Translation Unit 2 - Address of staticFunc: 0x5586be0f9349
Translation Unit 2 - Address of inlineFunc: 0x5586be0f931a

As seen in the above output, inlineFunc calls have the same address but the staticFunc calls have different addresses!

Hope this helps!

Comments

-7

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();

1 Comment

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.