Функции (inline
или нет) и макросы выполняют разные задачи.Их различие не следует рассматривать как идеологическое, как некоторые, кажется, считают, и, что еще более важно, они могут прекрасно работать вместе.
Макросы - это замена текста, которая выполняется во время компиляции, и они могут делать такие вещи, как:
#define P99_ISSIGNED(T) ((T)-1 < (T)0)
, который дает вам выражение времени компиляции того, подписан или нет целочисленный тип.То есть они идеально используются, когда тип выражения неизвестен (в определении), и вы хотите что-то с этим сделать.С другой стороны, ловушка с макросами заключается в том, что их аргументы могут быть оценены несколько раз, что плохо из-за побочных эффектов.
Функции (inline
) для других типизированы, что делает их более строгимиили, выражаясь отрицательно, менее гибким.Рассмотрим функции
inline uintmax_t absU(uintmax_t a) { return a; }
inline uintmax_t absS(uintmax_t a) {
return (-a < a) ? -a : a;
}
Первый реализует тривиальную функцию abs
для целого типа без знака.Второй реализует это для подписанного типа.(да, он принимает в качестве аргумента неподписанное, это для цели.)
Мы можем использовать их с любым целочисленным типом.Но тип возвращаемого значения всегда будет иметь наибольшую ширину, и возникнет определенная трудность при определении способа выбора между ними.
Теперь со следующим макросом
#define ABS(T, A) ((T)(P99_ISSIGNED(T) ? absS : absU)(A))
мы реализовали
- семейство функций
- , которое работает для любого целочисленного типа
- , которое оценивает свой аргумент только один раз
- , для которого любой недавний и достойный компиляторсоздаст оптимальный код
(Хорошо, я признаю, что делать это с abs
немного искусственно, но я надеюсь, что вы получите картину.)