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


214

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

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

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


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 */
}

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


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

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

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


6
Очевидно, нет; скобки предотвращают расширение макроса. Смотрите принятый ответ.
Кевин

12
@Kevin, мой ответ о показанном коде и правильный для него. Практически в любом C-вопросе здесь предполагается, что неизвестные определения препроцессора могут изменить все. В этом случае ответы, которые рассматривают препроцессор, действительно лучше, но это не делает мои неправильные.
Угорен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.