Я начал читать Effective C ++, и в какой-то момент в пункте 2 упоминается следующее:
// 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
Здесь число раз, которое a увеличивается перед вызовом f
зависит от того, с чем это сравнивается!
Действительно, если я использую простое утверждение печати в f
7 печатается в первом звонке, но я не могу понять, почему. Я что-то упускаю из виду?
Компилятор заменяет макросы именно тем, что вы передаете, дословно. Таким образом, вы в конечном итоге
int a = 5, b = 0;
f((++a) > (b) ? (++a) : (b));
f((++a) > (b+10) ? (++a) : (b+10));
использование g++ -E myprog.cpp
(заменить g++
с whatever-your-compiler-is
если вы не используете g++
) — он работает почти со всеми компиляторами, он будет производить реальный материал после предварительной обработки.
И это отличный пример того, почему вы не должны использовать макросы для выполнения функций типа вещи.
Вы бы получили гораздо больше того, что ожидали (вероятно), если бы использовали встроенную функцию:
inline void CallWithMax(int a, int b)
{
f((a) > (b) ? (a) : (b));
}
Любой достойный компилятор должен быть в состоянии сделать это по крайней мере так же эффективно, как макрос, с дополнительным преимуществом, что ваш a
а также b
оцениваются один раз в вызывающем коде, и ничего «странного» не происходит.
Вы также можете пройти через встроенную функцию, если вы строите свой код с отладочными символами, поэтому, если вы хотите увидеть, какое значение a
а также b
на самом деле внутри функции, вы можете сделать это. Макросы, потому что они расширяются до исходного места в исходном коде, так что вы не можете реально увидеть, что происходит внутри.