Макрос (предположительно) более эффективен, поскольку не требует вызова функции. Его можно оптимизировать проще, поскольку он включает в себя поиск смещения указателя.
Вызов функции позволяет создавать ссылки на одну и ту же библиотеку, даже если программа была скомпилирована без определения макроса - если она была скомпилирована с другим заголовком или просто с мошенническим объявлением внутри исходного файла. Если, например, у вас есть компилятор, у которого есть чья-то «улучшенная» версия ctype.h, у которой нет макроса, функция все равно будет существовать во время выполнения для использования.
Если мы посмотрим на стандарт:
c99
7.1.4 Использование библиотечных функций
Любая функция, объявленная в заголовке, может быть дополнительно реализована в виде функционально-подобного макроса, определенного в заголовке, поэтому, если библиотечная функция объявляется явно, когда включен ее заголовок, один из методов, показанных ниже, может использоваться для обеспечения того, чтобы объявление не было пострадал от такого макроса. Любое макроопределение функции может быть подавлено локально, заключив имя функции в круглые скобки, потому что за именем не следует левая скобка, которая указывает на расширение имени макрофункции. По той же синтаксической причине разрешается брать адрес библиотечной функции, даже если она также определена как макрос.
Это означает, что если вы напишите:
int b = (isdigit)(c);
или
int (*f)(int) = &isdigit;
int b = f(c);
тогда вы вызываете реальную функцию, а не макрос. Вы также можете по закону написать:
#undef isdigit
int b = isdigit(c);
или (в исходном файле нет #include <ctype.h>
прямого или транзитивного):
extern int isdigit(int);
int b = isdigit(c);