I have read in many books & tutorials that I should avoid macros in c++. Fine, but why? I don't get it. They are very useful and often used in C.
Could someone explain (very) detailed, why I should avoid them in C++?
I have read in many books & tutorials that I should avoid macros in c++. Fine, but why? I don't get it. They are very useful and often used in C.
Could someone explain (very) detailed, why I should avoid them in C++?
Macros don't respect scoping rules and operate at the textual level, as opposed to the syntax level. From this arise a number of pitfalls that can lead to strange, difficult to isolate bugs.
Consider the following well-known example:
#define max(a, b) ((a) < (b) ? (b) : (a))
⋮
int i = max(i++, j++);
The preferred alternative in this case is a function template:
template <typename T>
T max(const T & a, const T & b) { return a < b ? b : a; }
Here's another case that leads to subtle problems:
#define CHECK_ERROR(ret, msg) \
if (ret != STATUS_OK) { \
fprintf(stderr, "Error %d: %s\n", ret, msg); \
exit(1); \
}
⋮
if (ready)
CHECK_ERROR(try_send(packet), "Failed to send");
else
enqueue(packet);
You might think that the solution is as simple as wrapping the contents of CHECK_ERROR
in { … }
, but this won't compile due to the ;
before the else
.
To avoid the above problem (the else
attaching to CHECK_ERROR
's if
instead of the outer if
), one should wrap such macros in do … while (false)
as follows (and also avoid the duplicate ret
):
#define CHECK_ERROR(op, msg) \
do { \
int ret = (op); \
if (ret != STATUS_OK) { \
fprintf(stderr, "Error %d: %s\n", ret, msg); \
exit(1); \
} \
while (false)
This has no effect on the meaning of the macro, but ensures that the entire block is always treated as a single statement and doesn't interact in surprising ways with if
statements.
Long story short, macros are hazardous at many levels and should thus be used only as a last resort.
max(i++, j++)
⇒ ((i++) < (j++) ? (j++) : (i++))
. Note how whichever variable is the higher ends up being incremented twice. This is the essential problem with the fact that macros perform textual substitutions. –
Valeric CHECK_ERROR
that macro is going to execute try_send(packat)
twice, even in "fixed" code –
Caliche © 2022 - 2024 — McMap. All rights reserved.
MYMACRO(i++)
whereMYMACRO
is something likesomething((X), ... , (X), ...)
) – Grasping