Я добавлю к тому, что уже было сказано.
Поскольку макросы работают с подстановками текста, они позволяют вам делать очень полезные вещи, которые невозможно было бы сделать с помощью функций.
Вот несколько случаев, когда макросы могут быть действительно полезны:
/* Get the number of elements in array 'A'. */
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
Это очень популярный и часто используемый макрос. Это очень удобно, когда вам, например, нужно перебрать массив.
int main(void)
{
int a[] = {1, 2, 3, 4, 5};
int i;
for (i = 0; i < ARRAY_LENGTH(a); ++i) {
printf("a[%d] = %d\n", i, a[i]);
}
return 0;
}
Здесь не имеет значения, добавляет ли другой программист еще пять элементов к a
в объявлении. for
-loop будет всегда перебирать все элементы.
Функции библиотеки C для сравнения памяти и строк довольно уродливы.
Вы пишете:
char *str = "Hello, world!";
if (strcmp(str, "Hello, world!") == 0) {
/* ... */
}
или
char *str = "Hello, world!";
if (!strcmp(str, "Hello, world!")) {
/* ... */
}
Чтобы проверить, указывает ли str
на "Hello, world"
. Я лично думаю, что оба эти решения выглядят довольно некрасиво и запутанно (особенно !strcmp(...)
).
Вот два аккуратных макроса, которые некоторые люди (включая меня) используют, когда им нужно сравнить строки или память, используя strcmp
/ memcmp
:
/* Compare strings */
#define STRCMP(A, o, B) (strcmp((A), (B)) o 0)
/* Compare memory */
#define MEMCMP(A, o, B) (memcmp((A), (B)) o 0)
Теперь вы можете написать код так:
char *str = "Hello, world!";
if (STRCMP(str, ==, "Hello, world!")) {
/* ... */
}
Вот намерение намного яснее!
Это случаи, когда макросы используются для вещей, которые функции не могут выполнить. Макросы не должны использоваться для замены функций, но они могут использоваться и в других целях.