According to the C++ FAQ, macros are evil:
[9.5] Why should I use inline functions instead of plain old #define macros?
Because
#define
macros are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4. Sometimes you should use them anyway, but they're still evil. Unlike#define
macros, inline functions avoid infamous macro errors since inline functions always evaluate every argument exactly once. In other words, invoking an inline function is semantically just like invoking a regular function, only faster:// A macro that returns the absolute value of i #define unsafe(i) \ ( (i) >= 0 ? (i) : -(i) ) // An inline function that returns the absolute value of i inline int safe(int i) { return i >= 0 ? i : -i; } int f(); void userCode(int x) { int ans; ans = unsafe(x++); // Error! x is incremented twice ans = unsafe(f()); // Danger! f() is called twice ans = safe(x++); // Correct! x is incremented once ans = safe(f()); // Correct! f() is called once }
Also unlike macros, argument types are checked, and necessary conversions are performed correctly.
Macros are bad for your health; don't use them unless you have to.
Can someone explain why is unsafe(x++)
increments x
twice? I am not able to figure out.
"Macros are unsafe, have no type checking and should be avoided whenever possible. An alternative to macro is inline function for some use cases." He is right that a macro doesn't respect a namespace. That's just a caveat of using one.
Overview. Macro in C programming is known as the piece of code defined with the help of the #define directive. Macros in C are very useful at multiple places to replace the piece of code with a single value of the macro. Macros have multiple types and there are some predefined macros as well.
Function-like macros can take arguments, just like true functions. To define a macro that uses arguments, you insert parameters between the pair of parentheses in the macro definition that make the macro function-like. The parameters must be valid C identifiers, separated by commas and optionally whitespace.
A macro is a piece of code in a program that is replaced by the value of the macro. Macro is defined by #define directive. Whenever a macro name is encountered by the compiler, it replaces the name with the definition of the macro. Macro definitions need not be terminated by a semi-colon(;).
Running it through the preprocessor shows the problem. Using gcc -E
(can also use cpp -P
, where the -P
option also suppresses generated #
lines),
inline int safe(int i) { return i >= 0 ? i : -i; } int f(); void userCode(int x) { int ans; // increment 1 increment 2 (one of these) // | | | // V V V ans = ( (x++) >= 0 ? (x++) : -(x++) ); ans = ( (f()) >= 0 ? (f()) : -(f()) ); ans = safe(x++); ans = safe(f()); }
As artless noise notes, the function f()
is also called twice by the unsafe
macro. Perhaps it's pure (has no side-effects) so it's not wrong, per se. But still suboptimal.
So, since inline functions are generally safer than function-like macros because they work on the same semantic level with the other basic elements: variables and expressions; and for manifest constants, enum
s can often be more tidy; what are the good uses of macros?
Setting constants known only at compile-time. You can define a macro from the command-line when compiling. Instead of
#define X 12
in the source file, you can add
-DX=12
to the cc
command. You can also #undef X
from the command-line with -UX
.
This allows things like conditional-compilation, eg.
#if X do this; #else do that; #endif while (loop);
to be controlled by a makefile, itself perhaps generated with a configure script.
X-Macros. The most compelling use for X-Macros, IMO, is associating enum
identifiers with printable strings. While it make look funny at first, it reduces duplication and synchronization issues with these kinds of parallel definitions.
#define NAMES(_) _(Alice) _(Bob) _(Caravaggio) _(DuncanIdaho) #define BARE(_) _ , #define STRG(_) #_ , enum { NAMES(BARE) }; char *names[] = { NAMES(STRG) };
Notice that you can pass a macro's name as an argument to another macro and then call the passed macro by using the argument as if it were itself a macro (because it is one). For more on X-Macros, see this question.
Macros effectively do a copy/paste before the program is compiled.
unsafe(x++)
Would become
( (x++) >= 0 ? (x++) : -(x++) )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With