33

I'm a C/C++ developer, and here are a couple of questions that always baffled me.

  • Is there a big difference between "regular" code and inline code?
  • Which is the main difference?
  • Is inline code simply a "form" of macros?
  • What kind of tradeoff must be done when choosing to inline your code?

Thanks

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Marcos Bento
  • 2,030
  • 4
  • 22
  • 19

16 Answers16

45

Performance

As has been suggested in previous answers, use of the inline keyword can make code faster by inlining function calls, often at the expense of increased executables. “Inlining function calls” just means substituting the call to the target function with the actual code of the function, after filling in the arguments accordingly.

However, modern compilers are very good at inlining function calls automatically without any prompt from the user when set to high optimisation. Actually, compilers are usually better at determining what calls to inline for speed gain than humans are.

Declaring functions inline explicitly for the sake of performance gain is (almost?) always unnecessary!

Additionally, compilers can and will ignore the inline request if it suits them. Compilers will do this if a call to the function is impossible to inline (i.e. using nontrivial recursion or function pointers) but also if the function is simply too large for a meaningful performance gain.

One Definition Rule

However, declaring an inline function using the inline keyword has other effects, and may actually be necessary to satisfy the One Definition Rule (ODR): This rule in the C++ standard states that a given symbol may be declared multiple times but may only be defined once. If the link editor (= linker) encounters several identical symbol definitions, it will generate an error.

One solution to this problem is to make sure that a compilation unit doesn't export a given symbol by giving it internal linkage by declaring it static.

However, it's often better to mark a function inline instead. This tells the linker to merge all definitions of this function across compilation units into one definition, with one address, and shared function-static variables.

As an example, consider the following program:

// header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP

#include <cmath>
#include <numeric>
#include <vector>

using vec = std::vector<double>;

/*inline*/ double mean(vec const& sample) {
    return std::accumulate(begin(sample), end(sample), 0.0) / sample.size();
}

#endif // !defined(HEADER_HPP)
// test.cpp
#include "header.hpp"

#include <iostream>
#include <iomanip>

void print_mean(vec const& sample) {
    std::cout << "Sample with x̂ = " << mean(sample) << '\n';
}
// main.cpp
#include "header.hpp"

void print_mean(vec const&); // Forward declaration.

int main() {
    vec x{4, 3, 5, 4, 5, 5, 6, 3, 8, 6, 8, 3, 1, 7};
    print_mean(x);
}

Note that both .cpp files include the header file and thus the function definition of mean. Although the file is saved with include guards against double inclusion, this will result in two definitions of the same function, albeit in different compilation units.

Now, if you try to link those two compilation units — for example using the following command:

⟩⟩⟩ g++ -std=c++11 -pedantic main.cpp test.cpp

you'll get an error saying “duplicate symbol __Z4meanRKNSt3__16vectorIdNS_9allocatorIdEEEE” (which is the mangled name of our function mean).

If, however, you uncomment the inline modifier in front of the function definition, the code compiles and links correctly.

Function templates are a special case: they are always inline, regardless of whether they were declared that way. This doesn’t mean that the compiler will inline calls to them, but they won’t violate ODR. The same is true for member functions that are defined inside a class or struct.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 4
    Dang, I've been searching for a fix like this forever... I had a header with function definition+implementation, but didn't inline. Although there were header guards, there were still multiple definitions... Finally found the fix :) – rubenvb Jun 10 '10 at 16:16
  • I feel like there *should* be a better way to handle template function definitions than using the specifiers `static` or `inline` (not that I can think of one that doesn't limit the number of types your function can be used on) ... wouldn't both cases result in larger binaries? Also, how does using the `inline` keyword come into play if the compiler "chooses to ignore the hint" because your template function is 25 lines of code? Is the result the same as the `static` specifier? Why is `inline` **better** than `static`? – Assimilater Jun 20 '16 at 23:25
  • 1
    @Assimilater It won't increase executable size because a modern compiler/linker will ensure that there's no redundant definition. Also, when I said that the compiler can ignore `inline` requests, this is only for the purpose of optimisation. The compiler must still ensure that ODR is satisfied (how it does that is up to the compiler, and doesn't imply that function calls are actually inlined; it just means that the compiler keeps track of multiple definitions and merges them). Lastly, my example was badly chosen because function templates are always inline. – Konrad Rudolph Jun 21 '16 at 06:58
  • @Assimilater I’ve updated my example and changed the text to clarify these points. I hope the answer is clearer now. – Konrad Rudolph Jun 21 '16 at 10:06
  • @KonradRudolph `using` in a header, eww lol. More on point: I think this example is better than the previous one. Just to clarify, if the compiler/linker optimizes away duplicate binary from `inline` definitions finding their way into multiple compilation units, wouldn't `static` do the same just as well? (We're now talking about cases where the definitions are in a header, which feels like its own kind of special case though it happens enough). In this case the `inline` keyword would be preferred to `static` only as a style rule, correct? As you say, `static` has enough meanings :P – Assimilater Jun 21 '16 at 18:26
  • @KonradRudolph Also, since the linker is resolving duplicate binary apparently (though totally believable), beyond the exception of template functions, is there any benefit to defining `inline` or `static` functions in headers? Maybe some ramifications for linked libraries? – Assimilater Jun 21 '16 at 18:30
  • I suppose if I'm worrying about effects of `inline` code in the headers of included linked libraries, I'm thinking about it too hard and really missing the point of `inline` code. I figure at that point I'll just let the compiler deal with it... – Assimilater Jun 21 '16 at 18:36
  • From reading the cppreference link you posted I gather that the key difference here would be if an `inline` function had a `static` variable in its body, that variable would be the same in all translation units since each compilation unit is given the same address. However, a `static` function with a `static` variable in its body would provide a different instance in each compilation unit. Correct? – Assimilater Jun 21 '16 at 18:41
  • http://stackoverflow.com/a/145952/310560 second to last bullet seems to say opposite of your last paragraph. Maybe I misunderstand? Maybe that's something newer in c++? – Assimilater Jun 21 '16 at 18:54
  • 1
    @Assimilater Briefly, [`using` type aliases](http://en.cppreference.com/w/cpp/language/type_alias) in header are totally fine, you may be confusing this with [`using namespace` declarations](http://en.cppreference.com/w/cpp/language/namespace), which are not fine. About the difference between `static` and `inline`: `static` definitions are only visible inside the compilation unit (internal linkage), and if you have duplicate functions with internal linkage the linker will *not* merge these. This means that `static`, but not `inline`, will create duplicate code. – Konrad Rudolph Jun 22 '16 at 08:27
  • 2
    @Assimilater Furthermore, as you found out yourself, inside `static` functions, function-static variables will refer to different entities, whereas in `inline` functions, function-static variables will refer to the same entity across translation units. See this example: https://gist.github.com/klmr/9e06284a1ca9152bee2bfc3b1df14003. In general there are few reasons to ever use `static` functions in C++. – Konrad Rudolph Jun 22 '16 at 09:36
41
  • Is there a big difference between "regular" code and inline code?

Yes and no. No, because an inline function or method has exactly the same characteristics as a regular one, most important one being that they are both type safe. And yes, because the assembly code generated by the compiler will be different; with a regular function, each call will be translated into several steps: pushing parameters on the stack, making the jump to the function, popping the parameters, etc, whereas a call to an inline function will be replaced by its actual code, like a macro.

  • Is inline code simply a "form" of macros?

No! A macro is simple text replacement, which can lead to severe errors. Consider the following code:

#define unsafe(i) ( (i) >= 0 ? (i) : -(i) )

[...]
unsafe(x++); // x is incremented twice!
unsafe(f()); // f() is called twice!
[...]

Using an inline function, you're sure that parameters will be evaluated before the function is actually performed. They will also be type checked, and eventually converted to match the formal parameters types.

  • What kind of tradeoff must be done when choosing to inline your code?

Normally, program execution should be faster when using inline functions, but with a bigger binary code. For more information, you should read GoTW#33.

Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
  • 3
    Worth a commment is that the programmer can only hint to the compiler to use inline code is upto the compiler to actually make the choice (even when methods are defined in the class). The compiler will only inline if analyasis indicates an advantage to do so – Martin York Sep 25 '08 at 16:09
  • My understanding is that you cannot even hint to the compiler any more. You can say `inline int f() { ... }` all you want, the compiler will see that as the equivalent of `int f () { ... }` as far as optimizations are concerned, and then run its own analysis to determine whether to inline. – David Stone May 05 '12 at 16:01
  • 1
    Modern compilers take it as a fairly strong hint, but they'll also inline functions where you don't specifically ask for it. This is actively problematic when you're running up against the size of L1 icache, as the inlining can actually slow things down significantly… – Donal Fellows Dec 17 '13 at 10:12
16

Inline code works like macros in essence but it is actual real code, which can be optimized. Very small functions are often good for inlining because the work needed to set up the function call (load the parameters into the proper registers) is costly compared to the small amount of actual work the method does. With inlining, there is no need to set up the function call, because the code is directly "pasted into" any method that uses it.

Inlining increases code size, which is its primary drawback. If the code is so big that it cannot fit into the CPU cache, you can get major slowdowns. You only need to worry about this in rare cases, since it is not likely you are using a method in so many places the increased code would cause issues.

In summary, inlining is ideal for speeding up small methods that are called many times but not in too many places (100 places is still fine, though - you need to go into quite extreme examples to get any significant code bloat).

Edit: as others have pointed out, inlining is only a suggestion to the compiler. It can freely ignore you if it thinks you are making stupid requests like inlining a huge 25-line method.

Sander
  • 25,685
  • 3
  • 53
  • 85
  • 1
    Keep in mind that inline functions are guaranteed to have the same semantics as the equivalent non-inlined functions. Macros can have unexpected side-effects. – Ferruccio Sep 25 '08 at 11:48
  • 1
    Inlining need not necessarily increase code size. E.g. a simple arithmetic operation is likely smaller when inlined than when realized by a function call. – Jo So Apr 08 '18 at 21:17
7
  • Is there a big difference between "regular" code and inline code?

Yes - inline code does not involve a function call, and saving register variables to the stack. It uses program space each time it is 'called'. So overall it takes less time to execute because there's no branching in the processor and saving of state, clearing of caches, etc.

  • Is inline code simply a "form" of macros?

Macros and inline code share similarities. the big difference is that the inline code is specifically formatted as a function so the compiler, and future maintainers, have more options. Specifically it can easily be turned into a function if you tell the compiler to optimize for code space, or a future maintainer ends up expanding it and using it in many places in their code.

  • What kind of tradeoff must be done when choosing to inline your code?

    • Macro: high code space usage, fast execution, hard to maintain if the 'function' is long
    • Function: low code space usage, slower to execute, easy to maintain
    • Inline function: high code space usage, fast execution, easy to maintain

It should be noted that the register saving and jumping to the function does take up code space, so for very small functions an inline can take up less space than a function.

-Adam

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Adam Davis
  • 91,931
  • 60
  • 264
  • 330
  • It's also worth noting that `inline` can sometimes take a *lot* less space than a function call in cases where many (or all) of a function's arguments are constants. For example, given `inline double distsquared(double dx, double dy, double dz) { return sqrt(x*x+y*y+z*z); }`, the code `d=distsquared(1.0, 2.0, z);` could be expanded to `d=z*z+5;` which could be more compact than the code to push three `double` arguments and then call a function. – supercat Jul 26 '15 at 23:08
2

It depends on the compiler...
Say you have a dumb compiler. By indicating a function must be inlined, it will put a copy of the content of the function on each occurrence were it is called.

Advantage: no function call overhead (putting parameters, pushing the current PC, jumping to the function, etc.). Can be important in the central part of a big loop, for example.

Inconvenience: inflates the generated binary.

Is it a macro? Not really, because the compiler still checks the type of parameters, etc.

What about smart compilers? They can ignore the inline directive, if they "feel" the function is too complex/too big. And perhaps they can automatically inline some trivial functions, like simple getters/setters.

PhiLho
  • 40,535
  • 6
  • 96
  • 134
2

Inline differs from macros in that it's a hint to the compiler (compiler may decide not to inline the code!) and macros are source code text generation before the compilation and as such are "forced" to be inlined.

Kasprzol
  • 4,087
  • 22
  • 20
1

Marking a function inline means that the compiler has the option to include in "in-line" where it is called, if the compiler chooses to do so; by contrast, a macro will always be expanded in-place. An inlined function will have appropriate debug symbols set up to allow a symbolic debugger to track the source where it came from, while debugging macros is confusing. Inline functions need to be valid functions, while macros... well, don't.

Deciding to declare a function inline is largely a space tradeoff -- your program will be larger if the compiler decides to inline it (particularly if it isn't also static, in which case at least one non-inlined copy is required for use by any external objects); indeed, if the function is large, this could result in a drop in performance as less of your code fits in cache. The general performance boost, however, is just that you're getting rid of the overhead of the function call itself; for a small function called as part of an inner loop, that's a tradeoff that makes sense.

If you trust your compiler, mark small functions used in inner loops inline liberally; the compiler will be responsible for Doing The Right Thing in deciding whether or not to inline.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
0

If you are marking your code as inline in f.e. C++ you are also telling your compiler that the code should be executed inline, ie. that code block will "more or less" be inserted where it is called (thus removing the pushing, popping and jumping on the stack). So, yes... it is recommended if the functions are suitable for that kind of behavior.

kitofr
  • 751
  • 1
  • 7
  • 11
0

"inline" is like the 2000's equivalent of "register". Don't bother, the compiler can do a better job of deciding what to optimize than you can.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • Inaccurate -- if you don't mark a function inline, the compiler isn't allowed to inline it without your approval. Thus, by using "inline", you're giving the compiler more options in making its better-than-the-programmer's decisions. – Charles Duffy Sep 25 '08 at 11:41
  • The as-if rule allows the compiler to inline a fucntion if it wishes. However, it can only do so if the function definition is visible. Due to the ODR this basically means the compiler cannot implicitly inline a function from a different TU. – Richard Corden Sep 25 '08 at 11:51
  • @Charles, not true. The compiler is allowed to do anything that does not change the semantic of the program. All modern compilers will inline trivial functions even if you don't declare them as inline. – Nils Pipenbrinck Sep 25 '08 at 12:01
  • To be exact: @Nils: this depends on compiler settings. With Visual Studio three degreess are possible (no inlineing, only inline, any suitable). @Richard Corden - Whole Program Optimization can inline even across TUs. – Suma Sep 25 '08 at 12:29
  • @Suma: Theoretically that is true. How many platform/compilers support WPO? The platforms I am required to support still use a very basic linker to do the job. Others have highlighted how some linkers still don't remove duplicate template instantiations. 'inline' will be here for a while yet. – Richard Corden Sep 25 '08 at 13:12
0

By inlining, the compiler inserts the implementation of the function, at the calling point. What you are doing with this is removing the function call overhead. However, there is no guarantee that your all candidates for inlining will actually be inlined by the compiler. However, for smaller functions, compilers always inline. So if you have a function that is called many times but only has a limited amount of code - a couple of lines - you could benefit from inlining, because the function call overhead might take longer than the execution of the function itself.

A classic example of a good candidate for inlining are getters for simple concrete classes.

CPoint
{
  public:

    inline int x() const { return m_x ; }
    inline int y() const { return m_y ; }

  private:
    int m_x ;
    int m_y ;

};

Some compilers ( e.g. VC2005 ) have an option for aggressive inlining, and you wouldn't need to specify the 'inline' keyword when using that option.

QBziZ
  • 3,170
  • 23
  • 24
0

I won't reiterate the above, but it's worth noting that virtual functions will not be inlined as the function called is resolved at runtime.

RC.
  • 27,409
  • 9
  • 73
  • 93
  • Virtual functions can be inlined, if the compiler knows the dynamic type of the object at the point of the call. For example, if you have a pointer or reference to a base class, it won't be inlined, if you have a derived object (not ptr/ref), it may be inlined. – KeithB Sep 25 '08 at 12:43
0

Inlining usually is enabled at level 3 of optimization (-O3 in case of GCC). It can be a significant speed improvement in some cases (when it is possible).

Explicit inlining in your programs can add some speed improvement with the cost of an incresed code size.

You should see which is suitable: code size or speed and decide wether you should include it in your programs.

You can just turn on level 3 of optimization and forget about it, letting the compiler do his job.

INS
  • 10,594
  • 7
  • 58
  • 89
0

The answer of should you inline comes down to speed. If you're in a tight loop calling a function, and it's not a super huge function, but one where a lot of the time is wasted in CALLING the function, then make that function inline and you'll get a lot of bang for your buck.

stu
  • 8,461
  • 18
  • 74
  • 112
0

First of all inline is a request to compiler to inline the function .so it is upto compiler to make it inline or not.

  1. When to use?When ever a function is of very few lines(for all accessors and mutator) but not for recursive functions
  2. Advantage?Time taken for invoking the function call is not involved
  3. Is compiler inline any function of its own?yes when ever a function is defined in header file inside a class
yesraaj
  • 46,370
  • 69
  • 194
  • 251
0

inlining is a technique to increase speed. But use a profiler to test this in your situation. I have found (MSVC) that inlining does not always deliver and certainly not in any spectacular way. Runtimes sometimes decreased by a few percent but in slightly different circumstances increased by a few percent.

If the code is running slowly, get out your profiler to find troublespots and work on those.

I have stopped adding inline functions to header files, it increases coupling but gives little in return.

0

Inline code is faster. There is no need to perform a function call (every function call costs some time). Disadvantage is you cannot pass a pointer to an inline function around, as the function does not really exist as function and thus has no pointer. Also the function cannot be exported to public (e.g. an inline function in a library is not available within binaries linking against the library). Another one is that the code section in your binary will grow, if you call the function from various places (as each time a copy of the function is generated instead of having just one copy and always jumping there)

Usually you don't have to manually decide if a function shall be inlined or not. E.g. GCC will decide that automatically depending on optimizing level (-Ox) and depending on other parameters. It will take things into consideration like "How big is the function?" (number of instructions), how often is it called within the code, how much the binary will get bigger by inlining it, and some other metrics. E.g. if a function is static (thus not exported anyway) and only called once within your code and you never use a pointer to the function, chances are good that GCC will decide to inline it automatically, as it will have no negative impact (the binary won't get bigger by inlining it only once).

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • Some corrections. You can pass a pointer to an inline function. The function can be "extern", but it's definition needs to be visible to each TU that uses it. The code *may* grow. AFAIK, GCC cannot yet do Whole Program Optimisation which is needed for full implicit inline. – Richard Corden Sep 26 '08 at 09:27
  • The GCC workaround for that is to glom all the code for a group of TU's together. There are several scripts for it. KDE does it. Downside is 800+ MB RAM usage during KDE compile. – Zan Lynx Dec 16 '08 at 03:04