Function-like macros and strange behavior

2019-02-25 00:21发布

问题:

I have started reading Effective C++ and at some point in item 2, the following is mentioned:

// call f with the maximum of a and b
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))

...

int a = 5, b = 0;
CALL_WITH_MAX(++a, b); // a is incremented twice
CALL_WITH_MAX(++a, b+10); // a is incremented once

Here, the number of times that a is incremented before calling f depends on what it is being compared with!

Indeed, if I use a simple print statement in f, 7 gets printed in the first call, but I cannot for the life of me figure out why. Am I missing something obvious?

回答1:

The compiler replaces the macros with exactly what you pass in, verbatim. So you end up with

int a = 5, b = 0;
f((++a) > (b) ? (++a) : (b));
f((++a) > (b+10) ? (++a) : (b+10));


回答2:

Use g++ -E myprog.cpp (replace g++ with whatever-your-compiler-is if you are not using g++) - it works on ALMOST all compilers, it will produce the actual stuff after preprocessing.

And this is a great example of why you shouldn't use macros to do function-type stuff.

You'd get much more of what you (probably) expect if you were to use an inline function:

 inline void CallWithMax(int a, int b) 
 {
     f((a) > (b) ? (a) : (b));
 }

Any decent compiler should be able to do this AT LEAST as efficient as a macro, with the added advantage that your a and b are evaluated once in the calling code, and nothing "weird" happens.

You can also step through a inline function if you build your code with debug symbols, so if you want to see what value a and b actually are inside the function, you can do that. Macros, because they expand into the original place in the source code, so you can't really see what's going on inside.