When Do Compilers Inline C++ Code

When do compilers inline C++ code?

Yes, the compiler can inline code even if it's not explicitly declared as inline.

Basically, as long as the semantics are not changed, the compiler can virtually do anything it wants to the generated code. The standard does not force anything special on the generated code.

Does the compiler decide when to inline my functions (in C++)?

Whether or not a fiunction is inlined is, at the end of the day, entirely up to
the compiler. Typically, the more complex a function is in terms of flow, the less likely the compiler is to inline it. and some functions, such as recursive ones, simply cannot be inlined.

The major reason for not inlining a function is that it would greatly increase the overall size of the code, preventing iot from being held in the processor's cache. This would in fact be a pessimisation, rather than an optimisation.

As to letting the programmer decide to shoot himself in the foot, or elsewhere, you can inline the function yourself - write the code that would have gone in the function at what would have been the function's call site.

What is the use of the `inline` keyword in C?

Note: when I talk about .c files and .h files in this answer, I assume you have laid out your code correctly, i.e. .c files only include .h files. The distinction is that a .h file may be included in multiple translation units.

static inline void f(void) {} has no practical difference with static void f(void) {}.

In ISO C, this is correct. They are identical in behaviour (assuming you don't re-declare them differently in the same TU of course!) the only practical effect may be to cause the compiler to optimize differently.

inline void f(void) {} in C doesn't work as the C++ way. How does it work in C? What actually does extern inline void f(void); do?

This is explained by this answer and also this thread.

In ISO C and C++, you can freely use inline void f(void) {} in header files -- although for different reasons!

In ISO C, it does not provide an external definition at all. In ISO C++ it does provide an external definition; however C++ has an additional rule (which C doesn't), that if there are multiple external definitions of an inline function, then the compiler sorts it out and picks one of them.

extern inline void f(void); in a .c file in ISO C is meant to be paired with the use of inline void f(void) {} in header files. It causes the external definition of the function to be emitted in that translation unit. If you don't do this then there is no external definition, and so you may get a link error (it is unspecified whether any particular call of f links to the external definition or not).

In other words, in ISO C you can manually select where the external definition goes; or suppress external definition entirely by using static inline everywhere; but in ISO C++ the compiler chooses if and where an external definition would go.

In GNU C, things are different (more on this below).

To complicate things further, GNU C++ allows you to write static inline an extern inline in C++ code... I wouldn't like to guess on what that does exactly

I never really found a use of the inline keyword in my C programs, and when I see this keyword in other people's code, it's almost always static inline

Many coders don't know what they're doing and just put together something that appears to work. Another factor here is that the code you're looking at might have been written for GNU C, not ISO C.

In GNU C, plain inline behaves differently to ISO C. It actually emits an externally visible definition, so having a .h file with a plain inline function included from two translation units causes undefined behaviour.

So if the coder wants to supply the inline optimization hint in GNU C, then static inline is required. Since static inline works in both ISO C and GNU C, it's natural that people ended up settling for that and seeing that it appeared to work without giving errors.

, in which I see no difference with just static.

The difference is just in the intent to provide a speed-over-size optimization hint to the compiler. With modern compilers this is superfluous.

What does compiler really do when a class inline function is called?

An optimizing compiler can inline as it wishes.

For example, you might compile and link an entire program with g++ -flto -O2 (link-time whole program optimization option of GCC...).

(caveat: using g++ -flto -O2 would slow down significantly your build process; basically everything is compiled nearly "twice", once at "compile" time, once at "link" time, where GIMPLE representation gets re-optimized)

You'll be surprised by what function calls get inlined (a lot of them could be). It is unrelated to static or not functions marked or not as inline.

So you should not care about inlining (it is an implementation and optimization detail), but you hope that the compiler will do a good job.

(sometimes with g++ you want to disable most inlining to ease debugging with gdb; then compile with g++ -fno-inline -Wall -Wextra -O0 -g)

So these inline functions will not be replaced by compiler when they are called outside the class, am I right?

You are wrong, this is just an implicit argument (see also that), and of course compilers are often inlining calls to member functions. In practice C++ would be inefficient if compilers did not that optimization (since many member functions -e.g. getters and setters- are quite short and quick).

Remember that C++ is a specification written in some report (it is not a compiler). Inlining is a quality of implementation issue, and may or not happen.

If you care about what do the compiler really does (and you should not care, but you need to avoid undefined behavior in your code), ask it to show the generated assembler code. With GCC compile with g++ -O2 -fverbose-asm -S to get a foo.s assembler file from a foo.cc translation unit.

inline in C++ and compiler

I'm answering the question my self!: Solution: After a few performance tests, the rule of thumb from Stroustrup is right! inlining Short functions like the .size() from vector can improve the performance (.size() calls are used frequently). But the impact is only noticeable for FREQUENTLY used functions. If a getter/setter method is used a lot, inlining it might increase the performance.

Stroustrup:

Don’t make statements about “efficiency” of code without first doing
time measurements. Guesses about performance are most unreliable.

When is inline ineffective? (in C)

inline does two things:

  1. gives you an exemption from the "one definition rule" (see below). This always applies.
  2. Gives the compiler a hint to avoid a function call. The compiler is free to ignore this.

#1 Can be very useful (e.g. put definition in header if short) even if #2 is disabled.

In practice compilers often do a better job of working out what to inline themselves (especially if profile guided optimisation is available).


[EDIT: Full References and relevant text]

The two points above both follow from the ISO/ANSI standard (ISO/IEC 9899:1999(E), commonly known as "C99").

In §6.9 "External Definition", paragraph 5:

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

While the equalivalent definition in C++ is explictly named the One Definition Rule (ODR) it serves the same purpose. Externals (i.e. not "static", and thus local to a single Translation Unit -- typically a single source file) can only be defined once only unless it is a function and inline.

In §6.7.4, "Function Specifiers", the inline keyword is defined:

Making a function an inline function suggests that calls to the function be as
fast as possible.[118] The extent to which such suggestions are effective is
implementation-defined.

And footnote (non-normative), but provides clarification:

By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline substitution’’. Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.

Summary: what most users of C and C++ expect from inline is not what they get. Its apparent primary purpose, to avoid functional call overhead, is completely optional. But to allow separate compilation, a relaxation of single definition is required.

(All emphasis in the quotes from the standard.)


EDIT 2: A few notes:

  • There are various restrictions on external inline functions. You cannot have a static variable in the function, and you cannot reference static TU scope objects/functions.
  • Just seen this on VC++'s "whole program optimisation", which is an example of a compiler doing its own inline thing, rather than the author.

When should I write the keyword 'inline' for a function/method?

Oh man, one of my pet peeves.

inline is more like static or extern than a directive telling the compiler to inline your functions. extern, static, inline are linkage directives, used almost exclusively by the linker, not the compiler.

It is said that inline hints to the compiler that you think the function should be inlined. That may have been true in 1998, but a decade later the compiler needs no such hints. Not to mention humans are usually wrong when it comes to optimizing code, so most compilers flat out ignore the 'hint'.

  • static - the variable/function name cannot be used in other translation units. Linker needs to make sure it doesn't accidentally use a statically defined variable/function from another translation unit.

  • extern - use this variable/function name in this translation unit but don't complain if it isn't defined. The linker will sort it out and make sure all the code that tried to use some extern symbol has its address.

  • inline - this function will be defined in multiple translation units, don't worry about it. The linker needs to make sure all translation units use a single instance of the variable/function.

Note: Generally, declaring templates inline is pointless, as they have the linkage semantics of inline already. However, explicit specialization and instantiation of templates require inline to be used.


Specific answers to your questions:

  • When should I write the keyword 'inline' for a function/method in C++?

    Only when you want the function to be defined in a header. More exactly only when the function's definition can show up in multiple translation units. It's a good idea to define small (as in one liner) functions in the header file as it gives the compiler more information to work with while optimizing your code. It also increases compilation time.

  • When should I not write the keyword 'inline' for a function/method in C++?

    Don't add inline just because you think your code will run faster if the compiler inlines it.

  • When will the compiler not know when to make a function/method 'inline'?

    Generally, the compiler will be able to do this better than you. However, the compiler doesn't have the option to inline code if it doesn't have the function definition. In maximally optimized code usually all private methods are inlined whether you ask for it or not.

    As an aside to prevent inlining in GCC, use __attribute__(( noinline )), and in Visual Studio, use __declspec(noinline).

  • Does it matter if an application is multithreaded when one writes 'inline' for a function/method?

    Multithreading doesn't affect inlining in any way.



Related Topics



Leave a reply



Submit