Why should I avoid macros in C++? [closed]
Asked Answered
C

1

6

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++?

Caudex answered 11/6, 2013 at 11:34 Comment(13)
Don't the books explain why?Strange
A quick google for "Why should I avoid macros in C++" brought up this: securecoding.cert.org/confluence/display/cplusplus/…Cumbrance
Well, you should avoid using a macro where some other feature provides a better alternative; otherwise use a macro. What sort of situations are you concerned about?Nonmaterial
@Strange Sad but true, no they dont :(Caudex
@CharlesBailey No specific situation. Just in general, why the hell should I avoid them? ;PCaudex
You shouldn't... where they are the best solution to whatever problem you are solving with a macro. Please be more specific as your question is impossible to answer succinctly in its current form.Nonmaterial
First ideas out of my mind: lack of namespace support, hard to debug, prone to bugs (scope bugs), not the C++ way (i.e. C++ often provides a better alternative), side effects with macros that reference multiple times an argument (think about MYMACRO(i++) where MYMACRO is something like something((X), ... , (X), ...))Grasping
Unless you're a Boost developer then treat them as Evil™.Chillon
Don't ever use macros when you want to create something generic, use templates for that.Mcclurg
for starters read gotw.ca/gotw/032.htm gotw.ca/gotw/077.htm and gotw.ca/gotw/063.htmSphery
And if you ever have to write macros, please use a unique prefix for all of yours. Macros don't have namespaces, so you have to fake namespaces yourself. Other C++ developers will thank you.Glynda
Like many things, this is a matter of opinion (for some bordering to a religious issue). There are better constructs in some cases, in other case Macros are just the right thing to do. If you look at a) most large Open Source projects b) at all major APIs you will find tons of Macros.Dafodil
Outgrowing MacrophobiaOpalina
V
16

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.

Valeric answered 11/6, 2013 at 11:40 Comment(4)
But it does the same, right? Why not macro instead of a templateCaudex
@Davlog: Think about how the macro expands: 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
your second example with CHECK_ERROR that macro is going to execute try_send(packat) twice, even in "fixed" codeCaliche
@BЈовић well spotted. Fixed.Valeric

© 2022 - 2024 — McMap. All rights reserved.