Что означают скобки вокруг имени функции?

214

В одном из исходных файлов моего проекта я нашел определение функции C:

int (foo) (int *bar)
{
    return foo (bar);
}

Примечание: рядом нет звездочки foo, поэтому это не указатель на функцию. Либо это? Что здесь происходит с рекурсивным вызовом?

user1859094
источник
7
Нет, это не указатель на функцию - это все еще обычная функция с именем foo.
Неманья Борич
Это полная функция?
asheeshr
2
у вас есть доказательства того, что эта функция используется в полезном контексте?
moooeeeep
1
... выглядит как некая фиктивная функция, которая, возможно, была только что написана, чтобы увидеть, если она компилируется в существующем источнике и должна была быть удалена. Я бы удалил его (если это действительно то, что делает функция), поскольку в лучшем случае это будет бесконечный цикл (я не уверен, что компилятору C разрешено оптимизировать этот хвостовой вызов для перехода), в худшем - переполнение стека.
Hyde
3
Скобки в декларациях C помогают избежать неоднозначности в языке. Быстро, что это a(b);? Объявление bв качестве переменной типа a? Или вызов функции aс аргументом b? Разница в синтаксисе, и вы не можете знать, каким образом ее анализировать, не просматривая информацию объявления a; т. е. те скобки постфиксного вызова функции или необязательные скобки вокруг декларатора.
Каз

Ответы:

329

В отсутствие каких-либо препроцессорных вещей, foo подпись эквивалентна

int foo (int *bar)

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

Поначалу эта практика может показаться немного странной, но библиотека C создает прецедент, предоставляя некоторые макросы и функции с одинаковыми именами. .

Одна такая пара функция / макрос isdigit(). Библиотека может определить это следующим образом:

/* the macro */
#define isdigit(c) ...

/* the function */
int (isdigit)(int c) /* avoid the macro through the use of parentheses */
{
  return isdigit(c); /* use the macro */
}

Ваша функция выглядит почти так же, как и выше, поэтому я подозреваю, что это происходит и в вашем коде.

NPE
источник
2
Это может иметь место и здесь; Я не искал макросы ... И я не знал, что расширение макросов не происходит в скобках, спасибо за указание на это!
user1859094
13
@ user1859094: На второй взгляд, это почти наверняка то, что происходит в вашем коде. foo(bar)Внутри функции с использованием соответствующего макро.
NPE
78
@ user1859094 раскрытие макроса происходит в круглых скобках, но раскрытие функционально-подобного макроса происходит только в том случае, если следующий токен является левой скобкой (C99, 6.10.3§10), поэтому foo (int* bar)будет заменен, но не будет (foo) (int *bar)(следующий токен после того, fooкак ))
Virgile
4
Как будет называться такая функция? Вы бы тоже назвали это скобками? Например, это будет работать: (isdigit)(5)?
gcochard
4
@ Грег: Да, именно так вы бы это назвали.
NPE
37

Парантезы не изменяют объявление - оно все еще просто определяет обычную функцию с именем foo .

Причина, по которой они были использованы, почти наверняка заключается в том, что существует макрос, похожий на функцию с именем fooопределен:

#define foo(x) ...

Использование (foo)в объявлении функции предотвращает расширение этого макроса здесь. Так что, вероятно, происходит то, что функция foo()определяется с расширением ее тела из макроса, подобного функции foo.

кафе
источник
5
Хороший вывод (хотя использование скобок для этой цели должно преследоваться по закону).
Угорен
3
@ugoren: использование скобок вокруг имени функции - единственный способ предотвратить расширение макроса для макроса, подобного функции. Иногда это необходимый инструмент.
Майкл Берр
7
@MichaelBurr, есть также возможность не иметь макрос и функцию с одинаковым именем. Я знаю, что вы не всегда можете все контролировать, но если бы вы достигли этого решения, я бы сказал, что что-то очень неправильно.
Угорен
-3

Скобки не имеют смысла.
Код, который вы показываете, является ничем иным, как бесконечной рекурсией.

При определении указателя на функцию вы иногда видите странные скобки, которые что-то значат. Но это не тот случай, здесь.

ugoren
источник
6
Очевидно, нет; скобки предотвращают расширение макроса. Смотрите принятый ответ.
Кевин
12
@Kevin, мой ответ о показанном коде и правильный для него. Практически в любом C-вопросе здесь предполагается, что неизвестные определения препроцессора могут изменить все. В этом случае ответы, которые рассматривают препроцессор, действительно лучше, но это не делает мои неправильные.
Угорен