Подтвердить что ты не робот

Fputc vs putc в C

Я читал книгу программирования C Керниганом и наткнулся на это. Разница между двумя или их соответствующими критериями использования. Я нашел несколько сообщений в StackOverflow, которые касались этой проблемы. Я получил часть своего ответа, но с небольшими проблемами понял их.

Как упоминалось здесь (putc требует stdout, vs puts):

  • Согласно книге Кернигана putc эквивалентна fputc, но putc может быть реализована как макрос, а putc может оценивать свой аргумент потока более одного раза.

  • Разница между putc и fputc заключается в том, что с помощью putc вы рискуете запустить версию макроса, которая по своей сути является небезопасной, потому что ей, возможно, придется оценивать ее аргумент потока более одного раза. Это вызывает осложнения, о которых большинство людей не знает и, следовательно, не следит за ними, поэтому лучше использовать fputc. Макрос fputc не имеет этой проблемы.

Вопросы:

  • putc может быть реализован как макрос, но в чем проблема с тем же, что и с fputc?

  • Во втором заявлении упоминаются некоторые осложнения и проблемы безопасности. Что это такое?

  • putc оценивает свой аргумент более одного раза. Итак, каковы преимущества или недостатки, которые он представляет по сравнению с оценкой аргумента.

4b9b3361

Ответ 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(). Поскольку это не макрос, он не имеет никаких потенциальных проблем с оценкой своих аргументов более одного раза. Иногда макросы могут быть опасны, поэтому используйте их с осторожностью.