Inline functions vs Preprocessor macros
Asked Answered
S

14

137

How does an inline function differ from a preprocessor macro?

Sidoney answered 16/7, 2009 at 13:26 Comment(2)
Answers to #133238 contains some information related to your question.Shorthorn
This page has a very good explanation: icarus.cs.weber.edu/~dab/cs1410/textbook/6.Functions/… Waback machine linkHanghangar
K
141

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.
Kyla answered 16/7, 2009 at 13:33 Comment(7)
Inline function are not always guaranteed to be inlined: Because the compiler will not inline if doing so will generate slower code etc. The compiler does a lot of analysis that the Engineer can not and does the correct thing.Suomi
I believe that recursive functions are another example where most compilers ignore inlining.Kyla
Are there any important differences in C compared to C++ in this case?Lathan
One point not mentioned is that inlining can be influenced by compilation flags. For example, when you build for maximum speed (like GCC -O2/-O3) compiler will choose to inline many functions, but when you build for minimum size (-Os) if will typically inline functions called only once (or very small functions). With macros there is no such choice.Neurovascular
Macros can't cover with access specifier (like, private or protected) while inline functions are possible.Candelabra
There are directives supported by most compilers that can force an inline, regardless of compiler optimization level.Beirut
To prevent the macro function having unwanted side effects and allow the macro function to declare a temporary variable, GNU C provides statement expression (as an extension of the standard C), which is a compound statement enclosed in the parentheses () (e.g., ( { } ). For the details, please refer this [link]()Burns
F
90

First, the preprocessor macros are just "copy paste" in the code before the compilation. So there is no type checking, and some side effects can appear

For example, if you want to compare 2 values:

#define max(a,b) ((a<b)?b:a)

The side effects appear if you use max(a++,b++) for example (a or b will be incremented twice). Instead, use (for example)

inline int max( int a, int b) { return ((a<b)?b:a); }
Fleeta answered 16/7, 2009 at 13:36 Comment(4)
Just want to add to your example that besides side effect, macro can also introduce extra work load, consider max(fibonacci(100), factorial(10000)) the larger one will get calculated twice :(Export
Everybody speaks about Type Checking but just you provided a real-world example, that's why I upvote this answer.Barbour
@Export Why would the larger one get calculated twice? Thanks in advance!Nephology
In the macro, Why will a or b be incremented twice? It's because the max(a++, b++) will be replaced with (a++ < b++) ? b++ : a++, correct? I guess that also answers my above question (in regards to @Export 's comment). Thanks in advance!Nephology
E
19

The inline functions are expanded by the compiler where as the macros are expanded by the preprocessor which is a mere textual substitution.

Hence,

  • There is no type checking during macro invocation while type checking is done during function call.

  • Undesired results and inefficiency may occur during macro expansion due to reevaluation of arguments and order of operations. For example:

    #define MAX(a,b) ((a)>(b) ? (a) : (b))
    int i = 5, j = MAX(i++, 0);
    

    would result in

    int i = 5, j = ((i++)>(0) ? (i++) : (0));
    
  • The macro arguments are not evaluated before macro expansion

     #include <stdio.h>
     #define MUL(a, b) a*b
    
     int main()
     {
         // The macro is expended as 2 + 3 * 3 + 5, not as 5*8
         printf("%d", MUL(2+3, 3+5));
         return 0;
     }
     // Output: 16
    
  • The return keyword cannot be used in macros to return values as in the case of functions.

  • Inline functions can be overloaded.

  • The tokens passed to macros can be concatenated using operator ## called Token-Pasting operator.

  • Macros are generally used for code reuse where as inline functions are used to eliminate the time overhead (excess time) during function call (avoiding a jump to a subroutine).

Epizoic answered 5/10, 2014 at 10:52 Comment(0)
S
13

The key difference is type checking. The compiler will check whether what you pass as input values is of types that can be passed into the function. That's not true with preprocessor macros - they are expanded prior to any type checking and that can cause severe and hard to detect bugs.

Here are several other less obvious points outlined.

Streeto answered 16/7, 2009 at 13:27 Comment(0)
A
12

To add another difference to those already given: you can't step through a #define in the debugger, but you can step through an inline function.

Abernathy answered 16/7, 2009 at 13:39 Comment(0)
H
8

Macros are ignoring namespaces. And that makes them evil.

Hagioscope answered 16/7, 2009 at 13:34 Comment(0)
A
3

inline functions are similar to macros (because the function code is expanded at the point of the call at compile time), inline functions are parsed by the compiler, whereas macros are expanded by the preprocessor. As a result, there are several important differences:

  • Inline functions follow all the protocols of type safety enforced on normal functions.
  • Inline functions are specified using the same syntax as any other function except that they include the inline keyword in the function declaration.
  • Expressions passed as arguments to inline functions are evaluated once.
  • In some cases, expressions passed as arguments to macros can be evaluated more than once. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • macros are expanded at pre-compile time, you cannot use them for debugging, but you can use inline functions.

-- good article: http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;

Apprehend answered 16/7, 2009 at 14:11 Comment(0)
P
3

To know the difference between macros and inline functions, first we should know what exactly they are and when we should use them.

FUNCTIONS:

int Square(int x)
{
    return(x*x);
}

int main()
{
    int value = 5;
    int result = Square(value);
    cout << result << endl;
}
  • Function calls have overhead associated with them. After the function finishes executing it needs to know where to return to, so it stores the return address on the stack before calling the function. For small applications this might not be a problem, but in, say, a financial application, where thousands of transactions are happening every second, a function call might be too expensive.

MACROS:

# define Square(x) x*x;
int main()
{
    int value = 5;
    int result = Square(value);
    cout << result << endl;
}
  • Macros are applied in the preprocessing stage. During this stage the statements written with #define keywords will be replaced or expanded

int result = Square(x*x)

But macros can cause unexpected behavior.

#define Square(x) x*x
int main()
{
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
}

Here the output is 11, not 36.

INLINE FUNCTIONS:

inline int Square(int x)
{
    return x * x;
}

int main()
{
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
}

Output: 36

The inline keyword requests that the compiler replace the function call with the body of the function. Here the output is correct because it first evaluates the expression and then uses the result to perform the body of the function. Inline functions reduce the function call overhead as there is no need to store a return address or function arguments to the stack.

Comparison Between Macros and Inline Functions:

  1. Macros work through text substitution, whereas inline functions duplicate the logic of a function.
  2. Macros are error prone due to substitution while inline functions are safe to use.
  3. Macros can't be assigned to function pointers; inline functions can.
  4. Macros are difficult to use with multiple lines of code, whereas inline functions are not.
  5. In C++ macros cannot be used with member functions whereas inline function could be.

CONCLUSION:

Inline functions are sometimes more useful than macros, as they are safe to use, but can also reduce function call overhead. The inline keyword is a request to the compiler, certain functions won't be inlined like:

  • large functions
  • functions having too many conditional arguments
  • recursive code and code with loops etc.

which is a good thing, because it allows the compiler to determine whether it would be better to do things another way.

Parabola answered 8/6, 2020 at 6:37 Comment(1)
Just as a remark: The macro can be fixed to evaluate to the same number with brackets. However, it is still error prone, since you need to think about the absolute dumb subsitution and all cases during implementation.Larval
N
2

An inline function will maintain value semantics, whereas a preprocessor macro just copies the syntax. You can get very subtle bugs with a preprocessor macro if you use the argument multiple times - for example if the argument contains mutation like "i++" having that execute twice is quite a surprise. An inline function will not have this problem.

Nonagon answered 16/7, 2009 at 13:30 Comment(0)
Q
1

A inline functuion behaves syntactically just like a normal function, providing type safety and a scope for function local variables and access to class-members if it is a method. Also when calling inline methods you must adhere to private/protected restrictions.

Q answered 16/7, 2009 at 13:29 Comment(0)
G
0

In GCC (I'm not sure about others), declaring a function inline, is just a hint to the compiler. It is still up to the compiler at the end of the day to decide whether or not it includes the body of the function whenever it is called.

The difference between in-line functions and preprocessor macros is relatively large. Preprocessor macros are just text replacement at the end of the day. You give up a lot of the ability for the compiler to perform checking on type checking on the arguments and return type. Evaluation of the arguments is much different (if the expressions you pass into the functions have side-effects you'll have a very fun time debugging). There are subtle differences about where functions and macros can be used. For example if I had:

#define MACRO_FUNC(X) ...

Where MACRO_FUNC obviously defines the body of the function. Special care needs to be taken so it runs correctly in all cases a function can be used, for example a poorly written MACRO_FUNC would cause an error in

if(MACRO_FUNC(y)) {
 ...body
}

A normal function could be used with no problem there.

Glasgow answered 16/7, 2009 at 13:37 Comment(0)
L
0

From the perspective of coding, an inline function is like a function. Thus, the differences between an inline function and a macro are the same as the differences between a function and a macro.

From the perspective of compiling, an inline function is similar to a macro. It is injected directly into the code, not called.

In general, you should consider inline functions to be regular functions with some minor optimization mixed in. And like most optimizations, it is up to the compiler to decide if it actually cares to apply it. Often the compiler will happily ignore any attempts by the programmer to inline a function, for various reasons.

Lunation answered 16/7, 2009 at 13:42 Comment(0)
V
0

inline functions will behave as a function call if there exists any iterative or recursive statement in it, so as to prevent repeated execution of instructions. Its quite helpful to save the overall memory of your program.

Vociferate answered 17/1, 2014 at 21:53 Comment(0)
K
-1
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{ 
    return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases. 
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
 return a*a*a;
}
int main()
{
 cout<<NUMBER<<endl<<number()<<endl;
 cout<<CUBE(1+3); //Unexpected output 10
 cout<<endl<<cube(1+3);// As expected 64
 return 0;
}

Macros are typically faster than functions as they don’t involve actual function call overhead.

Some Disadvantages of macros: There is no type checking.Difficult to debug as they cause simple replacement.Macro don’t have namespace, so a macro in one section of code can affect other section. Macros can cause side effects as shown in above CUBE() example.

Macros are usually one liner. However, they can consist of more than one line.There are no such constraints in functions.

Keishakeisling answered 4/4, 2018 at 21:0 Comment(1)
How much more fun do you get from #define TWO_N(n) 2 << n and then cout << CUBE(TWO_N(3 + 1)) << endl;? (It's better to end lines of output with endl than to begin them with it.)Saffian

© 2022 - 2024 — McMap. All rights reserved.