[ fromfile: functions.xml id: inlinevsmacro ]
Macro expansion is a mechanism for placing code inline by means of a preprocessor directive:
#define MACRO_ID expr
This is different from an inline
function.
Macro expansion provides no type-checking for arguments.
It is essentially an editing operation: each occurrence of MACRO_ID
is replaced by expr.
Careful use of parentheses in macros is necessary to avoid precedence errors, but parentheses won't solve all the problems associated with macros, as you see in Example 5.19.
Errors caused by macros can lead to strange (and unclear) compiler errors or, more dangerously, to invalid results.
Example 5.19 demonstrates the latter situation.
Example 5.19. src/functions/inlinetst.cpp
// Inline functions vs macros #include <iostream> #define BADABS(X) (((X) < 0)? -(X) : X) #define BADSQR(X) (X * X) #define BADCUBE(X) (X) * (X) * (X) using namespace std; inline double square(double x) { return x * x ; } inline double cube(double x) { return x * x * x; } inline int absval(int n) { return (n >= 0) ? n : -n; } int main() { cout << "Comparing inline and #define\n" ; double t = 30.0; int i = 8, j = 8, k = 8, n = 8; cout << "\nBADSQR(t + 8) = " << BADSQR(t + 8) << "\nsquare(t + 8) = " << square(t + 8) << "\nBADCUBE(++i) = " << BADCUBE(++i) << "\ni = " << i << "\ncube(++j) = " << cube(++j) << "\nj = " << j << "\nBADABS(++k) = " << BADABS(++k) << "\nk = " << k << "\nabsval(++n) = " << absval(++n) << "\nn = " << n << endl; }
<include src="src/functions/inlinetst.cpp" href="src/functions/inlinetst.cpp" id="inlinetstcpp" mode="cpp"/>
Here is its output.
Comparing inline and #define BADSQR(t + 8) = 278 square(t + 8) = 1444 BADCUBE(++i) = 1100 i = 11 cube(++j) = 729 j = 9 BADABS(++k) = 10 k = 10 absval(++n) = 9 n = 9
BADSQR(t+8)
gives the wrong results because
BADSQR(t + 8) = (t + 8 * t + 8) (preprocessor) = (30.0 + 8 * 30.0 + 8) (compiler) = (30 + 240 + 8) (runtime) = 278
More troubling, however, are the errors produced by BADCUBE
and BADABS
which both have sufficient parentheses to prevent the kind of error that occurred with BADSQR
.
Here is what happened with BADCUBE(++i)
.
BADCUBE(++i) = ((++i) * (++i)) * (++i) // left associativity = ((10) * (10)) * (11) = 1100
Preprocessor macros are used mostly for the following:
#ifndef/#define/#endif
wrapping around header files to avoid multiple inclusion
#ifdef/#else/#endif
to conditionally compile some parts of code but not others
__FILE__
and __LINE__
macros for debugging and profiling
In Qt, macros are used with code-generation to add dynamic features to QObject
s, such as properties, signals and slots.
When possible, inline
functions (or template functions) should be used instead of macros for code substitutions.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |