2

Apparently the preprocessor macros in C++ are

justifiably feared and shunned by the C++ community.

However, there are several cases where C++ macros are beneficial.

Seeing as preprocessor macros can be extremely useful and can reduce repetitive code in a very straightforward manner --

-- leaves me with the question, what exactly is it that makes preprocessor macros "evil", or, as the question title says, which feature (or removal of feature) would be needed from preprocessor macros to make them useful as a "good" development tool (instead of a fill-in that everyone's ashamed of when using it). (After all, the Lisp languages seem to embrace macros.)

Please Note: This is not about #include or #pragma or #ifdef. This is about #define MY_MACRO(...) ...

Note: I do not intend for this question to be subjective. Should you think it is, feel free to vote to move it to programmers.SE.

Community
  • 1
  • 1
Martin Ba
  • 37,187
  • 33
  • 183
  • 337
  • 1
    The question seems to assume a falsehood, that adding just one feature to macros would "fix" them. – Steve Jessop Aug 17 '11 at 09:39
  • @Steve Jessop: Yeap, it's like adding one feature to a knife would make it absolutely safe in terms of cutting oneself. That feature would be to lock the knife away. – sharptooth Aug 17 '11 at 09:44
  • 4
    LISP macros are not at all like preprocessor macros. – R. Martinho Fernandes Aug 17 '11 at 09:45
  • 1
    A macro that operates on an AST (taking an AST arguments and returning a well-formed AST as a result), a macro written in the same language as its host, a macro having an access to the current compilation context (symbol declarations, etc.) would be much safer and much more powerful. – SK-logic Aug 17 '11 at 09:45
  • @SK-logic: Sounds a lot like boo syntactic macros. – R. Martinho Fernandes Aug 17 '11 at 09:46
  • @R. Martinho Fernandes, yes, there are many languages with such a functionality - starting from Lisp itself, and including more modern things like Template Haskell, MetaOCaml, Converge, Nemerle, Boo, etc. – SK-logic Aug 17 '11 at 09:50
  • 2
    C++ has features to make most macros obsolete. There's no point improving macros just like there's no point improving asbestos. We use a *MUCH* better tool now to accomplish the same result. – tenfour Aug 17 '11 at 09:52
  • @Steve: I've edited so that it doesn't read as "add just one more feature". What I meant with "adding a feature" could also imply to *remove* some capability from the preprocessor-macros to make them *more* useful. – Martin Ba Aug 17 '11 at 12:08
  • @tenfour: Think about your statement "to make *most* macros obsolete". If there's still room for *some* macros, then there's got to be something about these that makes macros useful and could be improved, no? (Well, the core language could be improved/expanded, but maybe *then* there would still be *some* room for *some* macros. Etc.) – Martin Ba Aug 17 '11 at 12:11
  • Macros by principle go against what is favored in C++ development. The way to improve it is to eliminate it. The only reason they are sometimes still useful is when there's no practical alternative. – tenfour Aug 17 '11 at 12:14
  • 1
    @tenfour: There's too many cases where there's no *practical* (as opposed to theoretical) alternative, and even with C++11 many of theses cases will still be there. Maybe tweaking them a bit could make them safer *in addition to being there to stay*. :-) – Martin Ba Aug 17 '11 at 12:20
  • possible duplicate of [When are C++ macros beneficial?](http://stackoverflow.com/questions/96196/when-are-c-macros-beneficial) – bobobobo Mar 10 '12 at 15:48

7 Answers7

3

Macros are widely considered evil because the preprocessor is a stupid text replacement tool that has little to none knowledge of C/C++.

Four very good reasons why macros are evil can be found in the C++ FAQ Lite.

Where possible, templates and inline functions are a better choice. The only reason I can think of why C++ still needs the preprocessor is for #includes and comment removal.

A widely disputed advantage is to use it to reduce code repetition; but as you can see by the boost preprocessor library, much effort has to be put to abuse the preprocessor for simple logic such as loops, leading to ugly syntax. In my opinion, it is a better idea to write scripts in a real high-level programming language for code generation instead of using the preprocessor.

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • const's and constexpr's are probably worth mentioning as features that used to be faked with macros – jk. Aug 17 '11 at 10:34
  • I specifically did not mention the Boost PP library, as I get dizzy every time I look at it. ;-) However, I *did* mention BOOST_FOREACH (which is *not* part of the PP library) and which is something that really made me wonder whether macros are such a bad thing after all. (There's no counting how much `.begin()`s and `.end()`s BOOST_FOREACH has saved me. :-) – Martin Ba Aug 17 '11 at 12:03
  • @Martin: and C++0x adds the Range For syntax to obsolete `BOOST_FOREACH` and Variadic Templates to obsolete the uses of macros in the MPL library. – Matthieu M. Aug 17 '11 at 12:17
  • 1
    @Matthieu: so you could say that macros, in their full evil potential, are useful in C++ as a means of implementing proposed future language features (or at least some approximation of the real proposal) on the current standard. – Steve Jessop Aug 17 '11 at 12:21
  • 2
    @Steve: I guess that could be interpreted like this. My take was more than whenever a widespread use of macros for a given situation was encountered, the C++ commitee tried to extend the language so it would no longer be needed :) – Matthieu M. Aug 17 '11 at 12:42
  • The Boost PP doesn't abuse the preprocessor. Most of the ugliness comes from workarounds for buggy preprocessors. Now most compilers are compliant, except MSVC(which is probably never going to happen). – Paul Fultz II Jul 31 '12 at 13:38
  • @Paul: Boost PP uses the preprocessor for things it was not designed for, in a hacky and limited way. Things that are really trivial for a "real" programming language or even C++ templates. For example, `BOOST_PP_INC` "computes" `i + 1` using hard-coded solutions for `i in 1..256`, since the preprocessor cannot do arithmetic. Have a look at the source here: http://boost.cvs.sourceforge.net/viewvc/boost/boost/boost/preprocessor/arithmetic/inc.hpp?revision=1.3&view=markup – Ferdinand Beyer Jul 31 '12 at 22:08
  • @FerdinandBeyer I dont consider using pattern matching to be hackish. Futhermore, Boost PP(as well as Chaos PP) uses well defined behavior of the preprocessor to implement its algorithms. Using the preprocessor as it was designed(for scanning and expanding macros) does not equal abuse. Abuse is when you use the preprocessor as if it was another language(such as C++). – Paul Fultz II Jul 31 '12 at 22:34
  • @Paul: Well, let's just agree to disagree here ;) – Ferdinand Beyer Aug 03 '12 at 06:55
1

Most preprocessor abuse come from misunderstanding, to quote Paul Mensonides(the author of the Boost.Preprocessor library):

Virtually all issues related to the misuse of the preprocessor stems from attempting to make object-like macros look like constant variables and function-like macro invocations look like underlying-language function calls. At best, the correlation between function-like macro invocations and function calls should be incidental. It should never be considered to be a goal. That is a fundamentally broken mentality.

As the preprocessor is well integrated into C++, its easier to blur the line, and most people don't see a difference. For example, ask someone to write a macro to add two numbers together, most people will write something like this:

#define ADD(x, y) ((x) + (y))

This is completely wrong. Runs this through the preprocessor:

#define ADD(x, y) ((x) + (y))
ADD(1, 2) // outputs ((1) + (2))

But the answer should be 3, since adding 1 to 2 is 3. Yet instead a macro is written to generate a C++ expression. Not only that, it could be thought of as a C++ function, but its not. This is where it leads to abuse. Its just generating a C++ expression, and a function is a much better way to go.

Furthermore, macros don't work like functions at all. The preprocessor works through a process of scanning and expanding macros, which is very different than using a call stack to call functions.

There are times it can be acceptable for macros to generate C++ code, as long as it isn't blurring the lines. Just like if you were to use python as a preprocessor to generate code, the preprocessor can do the same, and has the advantage that it doesn't need an extra build step.

Also, the preprocessor can be used with DSLs, like here and here, but these DSLs have a predefined grammar in the preprocessor, that it uses to generate C++ code. Its not really blurring the lines since it uses a different grammar.

Paul Fultz II
  • 17,682
  • 13
  • 62
  • 59
1

Macros have one notable feature - they are very easy to abuse and rather hard to debug. You can write just about anything with macros, then macros are expanded into one-liners and when nothing works you have very hard time debugging the resulting code.

The feature alone makes one think ten times on whether and how to use macros for their task.

And don't forget that macros are expanded before actual compilation, so they automatically ignore namespaces, scopes, type safety and a ton of other things.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
1

The most important thing about macros is that they have no scope, and do not care about context. They are almost a dump text replacement tool. So when you #define max(.... then everywhere where you have a max it gets replaced; so if someone adds overly generic macro names in their headers, they tend to influence code that they were not intended to.

Another thing is that when used without care, they lead to quite hard to read code, since no one can easily see what the macro could evaluate to, especially when multiple macros are nested.

A good guideline is to choose unique names, and when generating boilerplate code, #undef them as soon as possible to not pollute the namespace.

Additionally, they do not offer type safety or overloading.

Sometimes macros are arguably a good tool to generate boilerplate code, like with the help of boost.pp you could create a macro that helps you creating enums like:

ENUM(xenum,(a,b,(c,7)));

which could expand to

enum xenum { a, b, c=7 };

std::string to_string( xenum x ) { .... }

Things like assert() that need to react on NDEBUG are also often easier to implement as macros

PlasmaHH
  • 15,673
  • 5
  • 44
  • 57
1

There a many uses where a C developper uses Macros and an C++ developper uses templates.

There obviously corner cases where they're useful, but most of the time it's bad habits from the C world applied to C++ by people that believe there such a language called C/C++

So it's easier to say "it's evil" than risking a developper misuses them.

Tristram Gräbener
  • 9,601
  • 3
  • 34
  • 50
0

Forcing the programmer to use proper naming for the macros... and better tools to track replacement of macros would fix most my problems. I can't really say I've had major issues so far... It's something you burn yourself with and learn to take special care later on. But they badly need better integration with IDEs, debuggers.

0
  1. Macros do not offer type safety
  2. Problems where parameters are executed twice e.g. #define MAX(a,b) ((a)>(b) ? (a) : (b)) and apply it for MAX(i++, y--)
  3. Problems with debugging as their names do not occur in the symbol table.
Ed Heal
  • 59,252
  • 17
  • 87
  • 127