The macro language in C and C++ is processed by a dedicated parser at the 'pre-processing' stage; the tokens are translated and the output is then fed into the input stream of the parser proper. #define
and #include
tokens are not recognized by the C or C++ parsers themselves.
This is important because it means that when a macro is said to be "expanded" it means literally that. Given
#define MAX(A, B) (A > B ? A : B)
int i = 1, j = 2;
MAX(i, j);
what the C++ parser sees is
(i > j ? i : j);
However if we use the macro with something more complex, the same expansion happens:
MAX(i++, ++j);
is expanded to
(i++ > ++j ? i++ : ++j);
If we pass something that makes a function call:
MAX(f(), g());
this will expand to
(f() > g() ? f() : g());
If the compiler/optimizer can demonstrate that f()
has no side-effects, then it will treat this as
auto fret = f();
auto gret = g();
(fret > gret) ? fret : gret;
If it can't, then it will have to call f() and g() twice, for example:
#include <iostream>
int f() { std::cout << "f()\n"; return 1; }
int g() { std::cout << "g()\n"; return 2; }
#define MAX(A, B) (A > B ? A : B)
int main() {
MAX(f(), g());
}
Live demo: http://ideone.com/3JBAmF
Similarly if we were calling an extern
function, the optimizer may not be able to avoid calling the function twice.