Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

macros

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

like image 202
Davlog Avatar asked Jun 11 '13 11:06

Davlog


People also ask

Why you shouldn't use macros?

Macros repeat poorly constructed code all over the place — so you really need to know what you are doing with your macros and test them thoroughly before deploying them everywhere, and you need to avoid jumping down a rabbit hole if you want to go and update them later.

Are macros necessary in C?

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.

Why are macros faster in C?

Macros are typically faster than functions as they don't involve actual function call overhead.

Is it OK to use macro?

A good rule of thumb would be to only use macros in single-player games where the macros can help you automate certain tedious processes. Those would truly be the best macros for gaming as there are no downsides to using them for yourself or others.


1 Answers

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:

#define CHECK_ERROR(ret, msg) \
  do { \
    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.

like image 175
Marcelo Cantos Avatar answered Oct 20 '22 00:10

Marcelo Cantos