In C++, what’s the difference between an inline function and a macro?
This question was asked in interviews with both Apple and Intuit.
The major difference between inline functions and macros is the way they are handled. Inline functions are parsed by the compiler, whereas macros are expanded by the C++ preprocessor. This difference creates other differences, as best illustrated by examples.
The C++ preprocessor implements macros by using simple text replacement. Suppose we have the following macro:
When the preprocessor comes across any occurrences of SUM(first, last) in the code, then that text will be replaced by (first + last). When would one want to use a macro? Usually when what you’re substituting for is very simple, and does not justify the overhead of a function call. Remember that function calls do incur overhead.
Inline functions, as mentioned earlier, are parsed by the compiler directly instead of the preprocessor. Inline functions look very similar to regular functions. Here is what an inline function implementation of the SUM macro would look like:
The difference between an inline function and a regular function is that wherever the compiler finds a call to an inline function, it writes a copy of the compiled function definition. However, with a regular function, a normal function call is generated.
The reason C++ has inline functions and macros is to eliminate the overhead incurred by function calls. However, the tradeoff of this is the fact that the program size increases with both macros and inline functions. Remember that inline functions look like regular functions, but macros are implemented with text replacement.
The fact that macros use text replacement creates the potential for bugs. Suppose we have the following code:
If you’re expecting that j will be assigned a value of 4 squared (16), then you would be wrong. Because of the text replacement, what actually happens is that the DOUBLE(++y) expands to ++y * ++y, which equals 4*5, giving us 20. This problem would not occur if DOUBLE were implemented as an inline function. Inline functions only evaluate their arguments once, so any side effects of evaluation happen only once.
Another problem with macros occurs with binding. Suppose we have a macro with two statements, and then we try to use that macro with an if statement. If we decide not to use the curly brackets with our if statement, then we will have something that looks like this:
Then you’re probably thinking that the macro will expand to this:
But what actually happens is that the if statement binds to the first expression in the macro. So this is what it really expands to:
If we had used an inline function instead of a macro, the problem shown above would not have occurred. This is because an inline function is treated as a single statement, so the entire function would be bound to the if statement.
Debugging macros is also difficult. This is because the preprocessor does the textual replacement for macros, but that textual replacement is not visible in the source code itself. Because of all this, it’s generally considered a good idea to use inline functions over macros.