Cosa significano le parentesi attorno al nome di una funzione?


214

In uno dei miei file sorgente del progetto, ho trovato questa definizione della funzione C:

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

Nota: non c'è un asterisco accanto foo, quindi non è un puntatore a funzione. O è? Cosa sta succedendo qui con la chiamata ricorsiva?


7
No, non è un puntatore a funzione - è ancora una normale funzione chiamata foo.
Nemanja Boric,

Questa è la funzione completa?
asheeshr,

2
hai prove che questa funzione è usata in un contesto utile?
Moooeeeep,

1
... sembra una funzione fittizia che forse è stata appena scritta per vedere se si compila, nella fonte esistente, e avrebbe dovuto essere rimossa. Lo rimuoverei (se è quello che fa davvero la funzione), dato che nella migliore delle ipotesi sarà un ciclo infinito (non sono sicuro che il compilatore C possa ottimizzare la chiamata di coda per saltare), nel peggior overflow dello stack.
hyde,

3
Le parentesi nelle dichiarazioni C aiutano a rendere ambiguo il linguaggio. Veloce, cos'è a(b);? Dichiarazione di bcome variabile di tipo a? O una chiamata per funzionare acon argomento b? La differenza è sintattica e non puoi sapere in che modo analizzarla senza cercare le informazioni sulla dichiarazione di a; vale a dire quelle parentesi di funzione postfissa o parentesi opzionali attorno a un dichiaratore.
Kaz,

Risposte:


329

In assenza di roba preprocessore in corso, foola firma è equivalente a

int foo (int *bar)

L'unico contesto in cui ho visto persone mettere parentesi apparentemente non necessarie attorno ai nomi delle funzioni è quando ci sono sia una funzione che una macro simile alla funzione con lo stesso nome e il programmatore vuole impedire l'espansione delle macro.

All'inizio questa pratica può sembrare un po 'strana, ma la libreria C stabilisce un precedente fornendo alcune macro e funzioni con nomi identici .

Una tale coppia funzione / macro è isdigit(). La libreria potrebbe definirlo come segue:

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

La tua funzione sembra quasi identica a quella sopra, quindi sospetto che sia ciò che sta accadendo anche nel tuo codice.


2
Questo può essere il caso anche qui; Non ho cercato le macro ... E non sapevo che l'espansione delle macro non avvenga tra parentesi, grazie per averlo sottolineato!
user1859094

13
@ user1859094: al secondo sguardo, questo è quasi certamente quello che sta succedendo nel tuo codice. L' foo(bar)interno della funzione utilizza la macro corrispondente.
NPE,

78
@ user1859094 l'espansione della macro avviene tra parentesi, ma l'espansione di una macro simile a una funzione avviene solo se il token successivo è una parentesi sinistra (C99, 6.10.3§10), quindi foo (int* bar)verrebbe sostituito, ma non (foo) (int *bar)(il token successivo dopo fooè ))
Virgile,

4
Come si chiamerebbe una tale funzione? Lo chiameresti anche tra parentesi? Ad esempio, questo funzionerebbe (isdigit)(5):?
gcochard,

4
@Greg: Giusto, è esattamente come lo chiameresti.
NPE,

37

Le parentesi non cambiano la dichiarazione - sta ancora definendo una normale funzione chiamata foo.

Il motivo per cui sono stati utilizzati è quasi certamente perché esiste una macro simile a una funzione chiamata foodefinita:

#define foo(x) ...

L'uso (foo)nella dichiarazione di funzione impedisce che questa macro venga espansa qui. Quindi ciò che sta probabilmente accadendo è che una funzione foo()viene definita con il suo corpo espanso dalla macro simile a una funzione foo.


5
Bella deduzione (sebbene l'uso di parentesi a questo scopo debba essere punito dalla legge).
ugoren,

3
@ugoren: l'uso di parentesi attorno al nome della funzione è l'unico modo per impedire un'espansione macro per una macro simile a una funzione. A volte è uno strumento necessario.
Michael Burr,

7
@MichaelBurr, c'è anche la possibilità di non avere una macro e una funzione con lo stesso nome. So che non puoi sempre controllare tutto, ma se raggiungessi questa soluzione, direi che qualcosa non va.
ugoren,

-3

Le parentesi sono insignificanti.
Il codice che mostri non è altro che una ricorsione infinita.

Quando si definisce un puntatore a funzione, a volte si vedono strane parentesi che significano qualcosa. Ma questo non è il caso qui.


6
Evidentemente no; le parentesi impediscono l'espansione della macro. Vedi la risposta accettata
Kevin,

12
@ Kevin, La mia risposta riguarda il codice mostrato ed è corretto per questo. In quasi tutte le domande C qui, supponendo che definizioni di preprocessore sconosciute possano cambiare tutto. In questo caso, le risposte che considerano il preprocessore sono davvero migliori, ma non rendono errate le mie.
ugoren,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.