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.