0

In a tutorial I saw they used preprocessor directives to define macro. Why should I use macros instead of normal functions.


// Why should I use this
#define GROW_CAPACITY(capacity) \
    ((capacity) < 8 ? 8 : (capacity) * 2)

// Instead of this
int GROW_CAPACITY(int capacity) {
  return capacity < 8 ? 8 : capacity * 2
}
Ata Ege
  • 40
  • 1
  • 7
  • 7
    Don't use macros unless you have no other option. Use proper variables and functions. – Jesper Juhl Jun 27 '23 at 09:14
  • 2
    if the video presented those two as equivalent alternatives they were lying to you. The macro can and should be replaced by a `constexpr` function though – 463035818_is_not_an_ai Jun 27 '23 at 09:16
  • 3
    In C++ macros (both function-like and as named constants) should be avoided as much as possible. There are better constructs (`constexpr` functions and variables) available. – Some programmer dude Jun 27 '23 at 09:20
  • Sidenote: Don't name functions with UPPERCASE letters. That's intended for macros. So this `int grow_capacity(int capacity)` is correct. – digito_evo Jun 27 '23 at 09:24
  • Macros made sense when compilers were very stupid and they had very limited resources. Thankfully, this era is now gone and C++ was extended to take advantage of this. Use `constexpr` functions if possible. – tstanisl Jun 27 '23 at 09:25
  • To make the macro equivalent to the function, you'd do it like this: `#define GROW_CAPACITY(capacity) [](auto x){ return x < 8 ? 8 : x * 2); }(capacity)`. Regardless, the preprocessor is The Devil™ and should be avoided when possible. In this case, with two options, take the non-macro option. – Eljay Jun 27 '23 at 11:58
  • 2
    Don't use macros as a replacement for functions for all the reasons everyone is saying. There are a few cases, however, when you explicitly *don't* want function-call semantics, and that's where it makes sense to use a macro. This comes up a lot in debug functions where you want to pass ```__FILE__``` or ```__LINE__``` or in logging functions where you want to check some log level and then conditionally print (if you made such a thing a function, the arguments are evaluated even if the log level is too low to print). They're definitely special cases, though. – user1806566 Jun 27 '23 at 14:26

2 Answers2

2

In old times when CPUs were measured in MHz and RAM was in Kb the macro would always be inlined into code making it an easy shorthand for simple and readable code with no overhead. In those days a function call cost more than you expected or wanted and could even be noticeable in tight loops. In a very low power device maybe this is still true.

Nowadays though, CPUs are so fast the compiler can do a lot more to optimise functions, the 2nd one would be inlined (or not, the compiler will know to figure out when is best) so there's no reason not to use the function. This is perhaps why macros have fallen out of fashion.

However they can still be useful for making code more readable, if used appropriately. Even in compilers that do not have a preprocessor you still see features like #if DEBUG as this kind of macro is immensely powerful, with zero overhead.

gbjbaanb
  • 51,617
  • 12
  • 104
  • 148
-2

The two fundamentals principles are:

  • Use constexpr function or variable if possible,
  • Don't use macros if not necessary.

You should follow these guidelines.

Zig Razor
  • 3,381
  • 2
  • 15
  • 35