Одним из важных преимуществ реализации на основе макросов является то, что она не привязана к какому-либо конкретному типу параметра. Функциональный макрос в C во многих отношениях действует как шаблонная функция в C ++ (шаблоны в C ++ родились как «более цивилизованные» макросы, кстати). В этом конкретном случае аргумент макроса не имеет конкретного типа. Это может быть абсолютно все, что можно преобразовать в тип unsigned long
. Например, если пользователь этого пожелает (и если он готов принять последствия, определенные реализацией), он может передать в этот макрос типы указателей.
В любом случае, я должен признать, что этот макрос - не лучший пример гибкости макросов, не зависящей от типа, но в целом эта гибкость оказывается полезной довольно часто. Опять же, когда определенная функциональность реализуется функцией, она ограничивается определенными типами параметров. Во многих случаях, чтобы применить аналогичную операцию к разным типам, необходимо предоставить несколько функций с разными типами параметров (и разными именами, поскольку это C), в то время как то же самое можно сделать только одним функционально-подобным макросом. Например, макрос
#define ABS(x) ((x) >= 0 ? (x) : -(x))
работает со всеми арифметическими типами, в то время как реализация на основе функций должна обеспечивать довольно много из них (я подразумеваю стандартные abs
, labs
, llabs
и fabs
). (И да, я знаю о традиционно упоминаемых опасностях такого макроса.)
Макросы не идеальны, но популярное изречение о том, что «функциональные макросы больше не нужны из-за встроенных функций», - просто чушь. Для полной замены функционально-подобных макросов C потребуются шаблоны функций (как в C ++) или, по крайней мере, перегрузка функций (как в C ++ снова). Без этого функциональные макросы являются и останутся чрезвычайно полезным основным инструментом в C.