inline, __inline, __forceinline
The inline and __inline specifiers instruct the compiler to insert a copy of the function body into each place the function is called.
inline function_declarator; __inline function_declarator; // Microsoft Specific __forceinline function_declarator; // Microsoft Specific
The insertion (called inline expansion or inlining) occurs only if the compiler's cost/benefit analysis show it to be profitable. Inline expansion alleviates the function-call overhead at the potential cost of larger code size.
The __forceinline keyword overrides the cost/benefit analysis and relies on the judgment of the programmer instead. Exercise caution when using __forceinline. Indiscriminate use of __forceinline can result in larger code with only marginal performance gains or, in some cases, even performance losses (due to increased paging of a larger executable, for example).
Using inline functions can make your program faster because they eliminate the overhead associated with function calls. Functions expanded inline are subject to code optimizations not available to normal functions.
The compiler treats the inline expansion options and keywords as suggestions. There is no guarantee that functions will be inlined. You cannot force the compiler to inline a particular function, even with the __forceinline keyword. When compiling with /clr, the compiler will not inline a function if there are security attributes applied to the function.
The inline keyword is available only in C++. The __inline and __forceinline keywords are available in both C and C++. For compatibility with previous versions, _inline is a synonym for __inline.
The inline keyword tells the compiler that inline expansion is preferred. However, the compiler can create a separate instance of the function (instantiate) and create standard calling linkages instead of inserting the code inline. Two cases where this can happen are:
-
Recursive functions.
-
Functions that are referred to through a pointer elsewhere in the translation unit.
These reasons may interfere with inlining, as may others, at the discretion of the compiler; you should not depend on the inline specifier to cause a function to be inlined.
As with normal functions, there is no defined order of evaluation of the arguments to an inline function. In fact, it could be different from the order in which the arguments are evaluated when passed using normal function call protocol.
The /Ob compiler optimization option helps to determine whether inline function expansion actually occurs.
/LTCG performs cross-module inlining regardless of whether it was requested in source code.
Example 1
// inline_keyword1.cpp
// compile with: /c
inline int max( int a , int b ) {
if( a > b )
return a;
return b;
}
A class's member functions can be declared inline either by using the inline keyword or by placing the function definition within the class definition.
Example 2
// inline_keyword2.cpp
// compile with: /EHsc /c
#include <iostream>
using namespace std;
class MyClass {
public:
void print() { cout << i << ' '; } // Implicitly inline
private:
int i;
};
Microsoft Specific
The __inline keyword is equivalent to inline.
Even with __forceinline, the compiler cannot inline code in all circumstances. The compiler cannot inline a function if:
-
The function or its caller is compiled with /Ob0 (the default option for debug builds).
-
The function and the caller use different types of exception handling (C++ exception handling in one, structured exception handling in the other).
-
The function has a variable argument list.
-
The function uses inline assembly, unless compiled with /Og, /Ox, /O1, or /O2.
-
The function is recursive and not accompanied by #pragma inline_recursion(on). With the pragma, recursive functions are inlined to a default depth of 16 calls. To reduce the inlining depth, use inline_depth pragma.
-
The function is virtual and is called virtually. Direct calls to virtual functions can be inlined.
-
The program takes the address of the function and the call is made via the pointer to the function. Direct calls to functions that have had their address taken can be inlined.
-
The function is also marked with the naked __declspec modifier.
If the compiler cannot inline a function declared with __forceinline, it generates a level 1 warning.
Recursive functions can be substituted inline to a depth specified by the inline_depth pragma, up to a maximum of 16 calls. After that depth, recursive function calls are treated as calls to an instance of the function. The depth to which recursive functions are examined by the inline heuristic cannot exceed 16. The inline_recursion pragma controls the inline expansion of a function currently under expansion. See the Inline-Function Expansion (/Ob) compiler option for related information.
END Microsoft Specific
For more information on using the inline specifier, see:
Defining a function as an 'inline' function causes Visual Studio to "hang" for many seconds when starting (debugging) your application with the debugger, BUT ONLY WHEN you have a breakpoint set on a statement in that inlined function.
Apparently the debugger, in its attempt to honor your wish to set the breakpoint, must first locate all of the places in your code where the function was "inlined", and set a separate breakpoint at each of those individual places (which obviously takes it a long while to do, especially if that "function" is also called in external DLLs that your program happens to be linked with or which are loaded at runtime).
If the function is declared 'inline' but was not actually inlined by the compiler (recall that the 'inline' keyword does not guarantee that the function will actually be inlined; it is only a request that the compiler, at its discretion, may decide not to honor), then the problem (hang or "slow debugging session startup") does not occur. It of course also doesn't occur if you don't set any breakpoints on any statements within the 'inline' function.
In my own case I was calling an inlined function in 39 different places within my main program and the same inlined function in 69 other places in an external DLL (which in my case happened to be a MFC extension DLL).
If this is determined to be the cause of the "hang" or slow startup, then simply code a temporary non-inline version of the same function and set your breakpoint on that instead.
For example:
The following will cause the problem, because the compiler will very likely inline each 'BEEP()' call (i.e. the "MyMessageBeep" function will not actually exist anywhere since the compiler will likely "inline" it everywhere 'BEEP()' is used):
#define BEEP() MyMessageBeep()
inline void MyMessageBeep()
{
MessageBeep( 0xFFFFFFFF ); // breakpoint here causes problem
}
The workaround is to simply specify the function as NOT being 'inline':
#define BEEP() MyMessageBeep()
void MyMessageBeep()
{
MessageBeep( 0xFFFFFFFF ); // breakpoint here works fine
}
I hope this helps others who have been frustrated by this particular behavior.
It would be nice if Microsoft would issue some type of "warning" message when you have a breakpoint set on a statement within a function that the compiler has inlined. Such a message would eliminate a lot of frustration and confusion in my opinion and be very helpful to the community.
Thank you.
- 12/26/2010
- David B. Trout