Inline functions vs Preprocessor macros
Preprocessor macros are just substitution patterns applied to your code. They can be used almost anywhere in your code because they are replaced with their expansions before any compilation starts.
Inline functions are actual functions whose body is directly injected into their call site. They can only be used where a function call is appropriate.
Now, as far as using macros vs. inline functions in a function-like context, be advised that:
- Macros are not type safe, and can be expanded regardless of whether they are syntatically correct - the compile phase will report errors resulting from macro expansion problems.
- Macros can be used in context where you don't expect, resulting in problems
- Macros are more flexible, in that they can expand other macros - whereas inline functions don't necessarily do this.
- Macros can result in side effects because of their expansion, since the input expressions are copied wherever they appear in the pattern.
- Inline function are not always guaranteed to be inlined - some compilers only do this in release builds, or when they are specifically configured to do so. Also, in some cases inlining may not be possible.
- Inline functions can provide scope for variables (particularly static ones), preprocessor macros can only do this in code blocks {...}, and static variables will not behave exactly the same way.
inline function vs macro function
Inline replaces a call to a function with the body of the function, however, inline is just a request to the compiler that could be ignored (you could still pass some flags to the compiler to force inline or use always_inline attribute with gcc).
A macro on the other hand, is expanded by the preprocessor before compilation, so it's just like text substitution, also macros are not type checked, inline functions are. There's a comparison in the wiki.
For the sake of completeness, you could still have some kind of type safety with macros, using gcc's __typeof__
for example, the following generate almost identical code and both cause warnings if used with the wrong types:
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
__attribute__((always_inline)) int max(int a, int b) {
return (a > b ? a : b);
}
Note: sometimes typeless macros are just what's needed, for example, have a look at how uthash uses macros to make any C structure hashable without resorting to casts.
Macro vs Inline
- Inline functions are functions. They just have an additional
inline
attribute to hint the compiler that it might be good to inline those functions as an optimization. It's been said that compilers might not even listen to that. From your point of view, inline functions are 100% equal to functions. It's an optimization technique for the compiler.
Macros are code-generation templates. You define a template such as#define ADD_ONE(x) x = x + 1;
, and the preprocessor (not the compiler) will simply replace those strings by your template strings. Macros means "string-substitution" (with a few rules). - Macros should be your last recourse. Use them when you would otherwise repeat code that doesn't need to be repeated.
- True and false. Macros are simply string-substitution. So the code is inline. Inline functions may not be inline (see #1), therefore they are not "also" inline. I should add that inline means that there is no function call made while running that code.
What's the difference in practice between inline and #define?
#define
is a preprocessor tool and has macro semantics. Consider this, if max(a,b)
is a macro defined as
#define max(a,b) ((a)>(b)?(a):(b))
:
Ex 1:
val = max(100, GetBloodSample(BS_LDL))
would spill extra innocent blood, because the function will actually be called twice. This might mean significant performance difference for real applications.
Ex 2:
val = max(3, schroedingerCat.GetNumPaws())
This demonstrates a serious difference in program logic, because this can unexpectedly return a number which is less than 3 - something the user would not expect.
Ex 3:
val = max(x, y++)
might increment y
more than one time.
With inline functions, none of these will happen.
The main reason is that macro concept targets transparency of implementation (textual code replace) and inline targets proper language concepts, making the invocation semantics more transparent to the user.
Inline functions vs Preprocessor macros
Preprocessor macros are just substitution patterns applied to your code. They can be used almost anywhere in your code because they are replaced with their expansions before any compilation starts.
Inline functions are actual functions whose body is directly injected into their call site. They can only be used where a function call is appropriate.
Now, as far as using macros vs. inline functions in a function-like context, be advised that:
- Macros are not type safe, and can be expanded regardless of whether they are syntatically correct - the compile phase will report errors resulting from macro expansion problems.
- Macros can be used in context where you don't expect, resulting in problems
- Macros are more flexible, in that they can expand other macros - whereas inline functions don't necessarily do this.
- Macros can result in side effects because of their expansion, since the input expressions are copied wherever they appear in the pattern.
- Inline function are not always guaranteed to be inlined - some compilers only do this in release builds, or when they are specifically configured to do so. Also, in some cases inlining may not be possible.
- Inline functions can provide scope for variables (particularly static ones), preprocessor macros can only do this in code blocks {...}, and static variables will not behave exactly the same way.
Related Topics
Initializer_List and Move Semantics
Where Is C Not a Subset of C++
Forward Declaration of Nested Types/Classes in C++
What Does the Question Mark Character ('') Mean in C++
How to Implement an Stl-Style Iterator and Avoid Common Pitfalls
Sfinae Working in Return Type But Not as Template Parameter
Programmatically Find the Number of Cores on a Machine
Why Does Omission of "#Include ≪String≫" Only Sometimes Cause Compilation Failures
Post-Increment and Pre-Increment Within a 'For' Loop Produce Same Output
Combining C++ and C - How Does #Ifdef _Cplusplus Work
Array[N] VS Array[10] - Initializing Array With Variable VS Numeric Literal
Converting Std::_Cxx11::String to Std::String
How to Construct a C++ Fstream from a Posix File Descriptor
What's the Best Free C++ Profiler For Windows
Why Does Cout Print Char Arrays Differently from Other Arrays