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

Davlog
  • 2,162
  • 8
  • 36
  • 60
  • 4
    Don't the books explain why? – juanchopanza Jun 11 '13 at 11:36
  • 2
    A quick google for "Why should I avoid macros in C++" brought up this: https://www.securecoding.cert.org/confluence/display/cplusplus/PRE00-CPP.+Avoid+defining+macros – Thorsten Dittmar Jun 11 '13 at 11:36
  • 4
    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? – CB Bailey Jun 11 '13 at 11:36
  • @juanchopanza Sad but true, no they dont :( – Davlog Jun 11 '13 at 11:37
  • @CharlesBailey No specific situation. Just in general, why the hell should I avoid them? ;P – Davlog Jun 11 '13 at 11:37
  • 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. – CB Bailey Jun 11 '13 at 11:39
  • 1
    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), ...)`) – Matthieu Rouget Jun 11 '13 at 11:39
  • Unless you're a Boost developer then treat them as Evil™. – Mark Garcia Jun 11 '13 at 11:41
  • Don't ever use macros when you want to create something generic, use templates for that. – cubuspl42 Jun 11 '13 at 11:41
  • for starters read http://www.gotw.ca/gotw/032.htm http://www.gotw.ca/gotw/077.htm and http://www.gotw.ca/gotw/063.htm – Balog Pal Jun 11 '13 at 11:42
  • 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. – R. Martinho Fernandes Jun 11 '13 at 11:42
  • 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. – Nicholaz Jun 11 '13 at 11:43
  • [Outgrowing Macrophobia](http://www.idinews.com/macroPhobe.html) – Agnius Vasiliauskas Jun 11 '13 at 11:52

1 Answers1

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.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • But it does the same, right? Why not macro instead of a template – Davlog Jun 11 '13 at 11:50
  • 7
    @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. – Marcelo Cantos Jun 11 '13 at 11:57
  • your second example with `CHECK_ERROR` that macro is going to execute `try_send(packat)` twice, even in "fixed" code – BЈовић May 30 '22 at 06:19
  • @BЈовић well spotted. Fixed. – Marcelo Cantos Jun 06 '22 at 09:52