O que significam os parênteses em torno de um nome de função?

214

Em um dos arquivos de origem do meu projeto, encontrei esta definição de função C:

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

Nota: não existe um asterisco ao lado foo, portanto não é um ponteiro de função. Ou é? O que está acontecendo aqui com a chamada recursiva?

user1859094
fonte
7
Não, não é um ponteiro de função - ainda é uma função regular chamada foo.
Nemanja Boric
Essa é a função completa?
Asheeshr #
2
você tem evidências de que essa função é usada em um contexto útil?
moooeeeep
1
... se parece com alguma função fictícia que talvez tenha sido escrita apenas para ver se é compilada, na fonte existente, e deveria ter sido removida. Eu o removia (se é isso que a função realmente faz), uma vez que, na melhor das hipóteses, será um loop infinito (não tenho certeza se o compilador C tem permissão para otimizar a chamada final para pular), na pior pilha de estouro.
Hyde
3
Parênteses nas declarações C ajudam a tornar o idioma ambíguo. Rápido, o que é a(b);? Declaração de bcomo uma variável do tipo a? Ou uma chamada para funcionar acom argumento b? A diferença é sintática, e você não pode saber de que maneira analisá-la sem consultar as informações da declaração a; ou seja, são parênteses de chamada de função postfix ou parênteses opcionais ao redor de um declarador.
Kaz

Respostas:

329

Na ausência de qualquer material do pré-processador, fooa assinatura é equivalente a

int foo (int *bar)

O único contexto em que vi pessoas colocando parênteses aparentemente desnecessários em torno de nomes de funções é quando há uma função e uma macro semelhante à função com o mesmo nome, e o programador deseja impedir a expansão da macro.

Essa prática pode parecer um pouco estranha no começo, mas a biblioteca C cria um precedente ao fornecer algumas macros e funções com nomes idênticos .

Um desses pares função / macro é isdigit(). A biblioteca pode defini-lo da seguinte maneira:

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

Sua função parece quase idêntica à acima, então eu suspeito que isso também está acontecendo no seu código.

NPE
fonte
2
Esse pode ser o caso aqui também; Não procurei macros ... E não sabia que a expansão de macros não ocorre entre parênteses. Obrigado por apontar isso!
user1859094
13
@ user1859094: Em uma segunda olhada, é quase certamente isso que está acontecendo no seu código. A parte foo(bar)interna da função está usando a macro correspondente.
NPE
78
A expansão de macro @ user1859094 ocorre entre parênteses, mas a expansão de uma macro semelhante à função ocorre apenas se o próximo token for um parêntese esquerdo (C99, 6.10.3§10), portanto, foo (int* bar)seria substituído, mas não (foo) (int *bar)(o próximo token depois fooé ))
Virgile
4
Como essa função seria chamada? Você chamaria isso entre parênteses também? Por exemplo, isso funcionaria (isdigit)(5):?
Gcochard
4
@ Greg: Certo, é exatamente assim que você chamaria.
NPE
37

Os parênteses não alteram a declaração - ainda está apenas definindo uma função comum chamada foo.

A razão pela qual eles foram usados ​​é quase certamente porque existe uma macro de função chamada foodefinida:

#define foo(x) ...

O uso (foo)na declaração de função impede que essa macro seja expandida aqui. Portanto, o que provavelmente está acontecendo é que uma função foo()está sendo definida com seu corpo sendo expandido a partir da macro semelhante à função foo.

caf
fonte
5
Dedução legal (embora o uso de parênteses para esse fim deva ser punível por lei).
Ugoren
3
@ugoren: usar parens em torno do nome da função é a única maneira de impedir a expansão de uma macro semelhante a uma função. Às vezes é uma ferramenta necessária.
Michael Burr
7
@ MichaelBurr, também há a opção de não ter uma macro e função com o mesmo nome. Eu sei que você nem sempre pode controlar tudo, mas se você alcançasse essa solução, eu diria que algo está muito errado.
ugoren
-3

Os parênteses não têm sentido.
O código que você mostra não passa de uma recursão infinita.

Ao definir um ponteiro de função, você às vezes vê parênteses estranhos que realmente significam algo. Mas este não é o caso aqui.

Ugoren
fonte
6
Evidentemente não; os parênteses impedem a expansão da macro. Veja a resposta aceita.
28412 Kevin
12
@ Kevin, minha resposta é sobre o código mostrado e é correto para ele. Em quase qualquer questão C aqui, supor que definições de pré-processador desconhecidas possam mudar tudo. Nesse caso, as respostas que consideram o pré-processador são realmente melhores, mas não tornam as minhas incorretas.
ugoren