2015-08-10 8 views
30

Stavo passando per l'argomento di associatività degli operatori C.Associatività dell'operatore di chiamata di funzione in C

Lì mi sono imbattuto in questo fatto che l'operatore di chiamata di funzione () ha un'associatività da sinistra a destra. Ma l'associatività viene in gioco solo quando più operatori della stessa precedenza si verificano in un'espressione. Ma non sono riuscito a trovare alcun esempio che coinvolge l'operatore di chiamata di funzione in cui l'associatività svolge un ruolo cruciale.

Ad esempio nella dichiarazione a = f(x) + g(x);, il risultato dipende dall'ordine di valutazione e non dall'associatività delle due chiamate di funzione. Analogamente la chiamata f(g(x)) valuterà prima la funzione g() e poi la funzione f(). Qui abbiamo una chiamata di funzione nidificata e ancora l'associatività non svolge alcun ruolo.

Gli altri operatori C in questo gruppo di priorità sono l'indice di serie [], postfix ++ e postfix --. Ma non sono riuscito a trovare esempi che coinvolgessero una combinazione di questi operatori con () in cui l'associatività gioca un ruolo nella valutazione dell'espressione.

Quindi la mia domanda è l'associatività della chiamata di funzione definita come da sinistra a destra interessa qualsiasi espressione in C? Qualcuno può fornire un esempio in cui l'associatività dell'operatore di chiamata di funzione () è importante nella valutazione delle espressioni?

+0

Cosa succede se 'f' è un'espressione in sé (come un puntatore a funzione selezionato da un array)? – EOF

+2

Qualsiasi funzione che restituisce un puntatore a una funzione può essere utilizzata come esempio, poiché la funzione di dereferenziazione del puntatore non è necessaria con l'operatore di chiamata di funzione. Quindi inizi ad avere cose come 'f()()()()' ed è valido C. Vedi la risposta di Grzegorz per un possibile esempio. –

+0

28 upvotes .... Deve essere lasciato a destra. Vorresti vivere in un mondo in cui 'f (a) (b)' era una chiamata a 'f' passando a' b', quindi chiamando il risultato con 'a' (vale a dire' (f (b)) (a) ') - vuoi? –

risposta

43

Ecco un esempio, dove a sinistra-destra associatività di questioni operatore chiamata di funzione:

#include <stdio.h> 

void foo(void) 
{ 
    puts("foo"); 
} 

void (*bar(void))(void) // bar is a function that returns a pointer to a function 
{ 
    puts("bar"); 
    return foo; 
} 

int main(void) 
{ 
    bar()(); 

    return 0; 
} 

La chiamata di funzione:

bar()(); 

è equivalente a:

(bar())(); 
+1

Brillante. Grazie mille. – Deepu

+1

Cancella * e * conciso. – David

+1

In che senso l'associatività è rilevante quando si tratta di operatori unari che sono tutti prefissi o tutti postfix? Penserei che sarebbe rilevante soprattutto nei casi in cui gli operatori prefisso e postfisso sono entrambi applicati allo stesso oggetto, come in '* pippo()'. Non riesco a pensare ad alcuna definizione di 'foo' che permetta a entrambi (* foo)()' e '* (foo())' di essere legali in C (una cosa del genere potrebbe esistere in C++), ma il Infatti ogni forma è legale in alcune situazioni e solo quest'ultima può essere sostituita con '* foo()' dimostrerebbe la relativa associatività di '*' e '()'. – supercat

15

In Oltre alla risposta di @ GrzegorzSzpetkowski, puoi anche avere:

void foo(void) { } 

int main(void) { 
    void (*p[1])(void); 
    p[0] = foo; 
    p[0](); 
    return 0; 
} 

Questo crea una matrice di puntatori di funzione, quindi è possibile utilizzare l'operatore di indice di matrice con l'operatore di chiamata di funzione.

+0

Bella risposta. Grazie. – Deepu

+2

E se quelle funzioni negli array fossero 'int * (* p [1]) (int)' invece, potresti avere 'p [0] (1) [2];'. Prendi il primo puntatore alla funzione, chiamalo con l'argomento 1 e prendi il terzo elemento dell'array restituito. Non c'è quasi alcun limite alla complessità delle espressioni C – MSalters

3

L'istruzione che l'applicazione di funzione associa a sinistra è completamente ridondante nella definizione del linguaggio C. Questa "associatività" è implicita dal fatto che una lista di argomenti di funzioni appare a destra dell'espressione di funzione stessa e deve essere racchiuso tra parentesi. Ciò significa che per una determinata espressione di funzione, non ci può essere alcun dubbio sull'estensione della sua lista di argomenti: si estende dalla parentesi di apertura obbligatoria dopo l'espressione di funzione alla parentesi di chiusura corrispondente.

L'espressione di funzione (che spesso è solo un identificatore, ma potrebbe essere più complicata) potrebbe essere essa stessa una chiamata di funzione (nuda), come in f(n)(1,0). (Ovviamente ciò richiede che il valore restituito da f(n) sia qualcosa che può essere chiamato con la lista degli argomenti (1,0), per cui C ha alcune possibilità e C++ molto di più, ma queste sono considerazioni semantiche che vengono solo a dopo l'analisi, quindi dovrebbero essere ignorati per la discussione associatività.) Ciò significa che la regola di sintassi per le chiamate di funzione è di tipo ricorsivo a sinistra (la parte di funzione può essere essa stessa una chiamata di funzione); questo può essere formulato dicendo "le chiamate di funzione si associano a sinistra", ma il fatto è ovvio.Al contrario, la parte destra (elenco argomenti) non può essere una chiamata di funzione (nuda) a causa delle parentesi richieste, quindi non può esserci una ricorsione corretta.

Ad esempio, considerare (a)(b)(c) (dove inserisco parentesi ridondante per suggerire simmetria e possibile ambiguità). Qui di per sé (b)(c) potrebbe essere considerata la chiamata di b (ridondante tra parentesi) con argomento c; tuttavia tale chiamata non può essere interpretata come argomento di a, poiché ciò richiederebbe parentesi aggiuntive come in (a)((b)(c)). Quindi, senza menzionare l'associatività, è chiaro che (a)(b)(c) può significare solo che viene chiamato con l'argomento b e che il valore risultante viene chiamato con l'argomento c.