Ответ 1
Проблема с реализацией макросов заключается в том, что если какой-либо из аргументов имеет побочные эффекты, эти побочные эффекты могут быть оценены более одного раза, что может привести к поведению undefined. Рассмотрим этот пример игрушки:
#define SQUARE(x) ((x) * (x))
В большинстве случаев это будет работать так, как ожидалось, но если вы передадите выражение, такое как f()
, побочный эффект вызова функции f()
произойдет дважды, а не один раз, поскольку препроцессор просто текстовый трансформатор, который не знает C:
int f()
{
printf("f() was called\n");
return 42;
}
...
int x = SQUARE(f()); // This calls f() twice! It gets expanded to this:
// int x = (f() * f());
Чтобы представить это в перспективе, функция putc
, если она реализована как макрос, может оценивать ее аргумент stream
более одного раза. Итак, если этот поток исходит из функции:
FILE *get_file()
{
// Potential side effects could happen here
return some_file;
}
...
putc('A', get_file());
Тогда это может привести к тому, что функция get_file()
получает вызов более одного раза с потенциально нежелательными побочными эффектами.
Решение, конечно, состоит в том, чтобы просто вызвать регулярную функцию, например fputc()
вместо putc()
. Поскольку это не макрос, он не имеет никаких потенциальных проблем с оценкой своих аргументов более одного раза. Иногда макросы могут быть опасны, поэтому используйте их с осторожностью.