Що означають дужки навколо назви функції?


214

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

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

Примітка: Поруч немає зірочки foo, тому це не покажчик функції. Або це? Що відбувається тут з рекурсивним викликом?


7
Ні, це не покажчик функції - це все-таки звичайна функція, названа foo.
Неманя Борич

Це повна функція?
asheeshr

2
чи є у вас докази того, що ця функція використовується у корисному контексті?
moooeeeep

1
... виглядає як якась фіктивна функція, яку, можливо, просто написали, щоб побачити, чи вона компілюється, у існуючому джерелі та її слід було видалити. Я б його видалив (якщо це дійсно функція), оскільки в кращому випадку це буде нескінченний цикл (я не впевнений, чи компілятору C дозволено оптимізувати цей хвіст для виклику), в гіршому випадку переповнення стека.
Гайд

3
Дужки в деклараціях С допомагають виправити мову неоднозначно. Швидкий, що таке a(b);? Декларація bяк змінної типу a? Або заклик функціонувати aз аргументом b? Різниця синтаксична, і ви не можете знати, який спосіб її навіть розібрати, не шукаючи інформацію про декларації a; тобто це круглі дужки виклику функції постфіксу або необов'язкові дужки навколо декларатора.
Каз

Відповіді:


329

За відсутності будь-яких матеріалів препроцесора, fooпідпис є рівнозначним

int foo (int *bar)

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

Така практика спочатку може здатися трохи дивною, але бібліотека С встановлює прецедент, надаючи деяким макросам і функціям однакові імена .

Однією з таких функцій / макропар є 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
Так може бути і тут; Я не шукав макросів ... І я не знав, що розширення макросів не відбувається в круглих дужках. Дякую, що вказали на це!
користувач1859094

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
@Greg: Так, саме так ви б назвали.
NPE

37

Парантези не змінюють декларацію - вона все ще просто визначає звичайну функцію, яку називають foo.

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

#define foo(x) ...

Використання (foo)в декларації функції запобігає розширенню цього макросу тут. Отже, що, ймовірно, відбувається, що функція foo()визначається з розширенням її тіла з макрокоманди, подібного до функції foo.


5
Приємне вирахування (хоча використання дужок для цієї мети повинно каратися законом).
ugoren

3
@ugoren: використання паролів навколо назви функції - це єдиний спосіб запобігти розширенню макросу для макроса, подібного до функції. Часом це необхідний інструмент.
Майкл Берр

7
@MichaelBurr, також є можливість не мати макросу та функції з тим самим іменем. Я знаю, що ти не завжди можеш контролювати все, але якби ти прийшов до цього рішення, я б сказав, що це щось не так.
ugoren

-3

Дужки безглуздо.
Показаний вами код - це не що інше, як нескінченна рекурсія.

Визначаючи покажчик функції, іноді ви бачите дивні дужки, які щось означають. Але це не так.


6
Очевидно, що ні; круглі дужки запобігають розширенню макросу. Дивіться прийняту відповідь.
Кевін

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