2013-05-16 16 views
11

vedere il codice qui di seguito, definire una funzione in un'altra funzione,Perché è possibile definire una funzione in un'altra funzione?

void test1(void) 
{ 
void test2(void) 
{ 
    printf("test2\n"); 
} 
printf("test1\n"); 
} 

int main(void) 
{ 
test1(); 
return 0; 
} 

questo uso è dispari, è un uso di C89/C99 oppure solo un'estensione di gcc (ho usato gcc 4.6.3 in ubuntu 12 compilato). Eseguo questo codice e restituisce "test2" e "test1" .test2 può essere chiamato solo in test1.

Inoltre, qual è la scena comune di questo utilizzo o per cosa viene utilizzato questo utilizzo?

+3

sua limitando la portata del 'test2()' non si può chiamare fuori 'test1()'. – bikram990

risposta

17

Sì, questo è un GCC extension.

Non è C, non è portatile, e quindi non molto consigliato se non sai che GCC sarà

  • essere l'unico compilatore utilizzato per costruire il vostro codice
  • Will continuare a sostenere questa funzionalità nelle versioni future
  • Non importa di principle of least astonishment.
+1

Ovviamente se si dispone di C++ 11, è possibile definire funzioni nidificate con lambda. – chris

+0

È possibile chiamare solo test1 ed escludere l'esecuzione di test2? – bjskishore123

+2

@ bjskishore123, 'auto test2 = [] {printf (" test2 \ n ");};' non lo eseguirà, ma agirà comunque come una definizione di funzione per quello che vale. – chris

4

Come scritto, non è legale C++. Tuttavia, è possibile definire una classe all'interno di una funzione e definire le funzioni in quella classe. Ma anche allora, in pre C++ 11, è ancora solo il nesting lessicale; la classe definita non "cattura" alcuno del contesto di la funzione esterna (a meno che non si implementi esplicitamente l'acquisizione ); in una funzione nidificata vera, la funzione nidificata può accedere alle variabili locali nella funzione esterna. In C++ 11, è possibile definire una funzione lambda, con acquisizione automatica.

Il motivo C e C++ non ha mai adottato funzioni nidificate è perché al fine di rendere il lavoro di acquisizione, avete bisogno di ulteriori informazioni, con il risultato che un puntatore a funzione diventa più complesso. Con il risultato che non è possibile prendere l'indirizzo della funzione nidificata (mancanza di ortogonalità), un puntatore a una funzione nidificata non è compatibile con un puntatore normale a una funzione (che finisce per richiedere troppi dettagli esterni per perculare out), o tutti i puntatori alle funzioni hanno le informazioni supplementari (e si paga per qualcosa che non si usa la maggior parte del tempo).

+0

La "cattura", intendevi "chiusura"? – Marcus

+2

@Marcus - "cattura" è l'intento, "chiusura" è un'implementazione. Solo il compilatore dovrebbe preoccuparsi della chiusura e potrebbe scegliere un'implementazione diversa (anche se le chiusure sono normali per una buona ragione). – Steve314

+0

Forse degno di nota: le funzioni nidificate (con acquisizione del contesto) sono state introdotte per la prima volta in linguaggi funzionali (prelevandole dal lambda calcolo) e tutte (o almeno la maggior parte) le lingue funzionali. Nel paradigma imperativo, la famiglia Pascal ha sempre avuto procedure nidificate e alcune delle famiglie C più recenti le hanno: sono abbastanza sicuro di C#, Java, JavaScript, D, ActionScript e probabilmente di più. – Steve314

0

Le funzioni annidate sono consentite solo in C, ma vengono utilizzate raramente perché sono visibili solo nell'ambito di questa funzione. Tuttavia, se si vuole aggirare funzioni nidificate si può fare qualcosa di simile

#include<stdio.h> 
typedef void (*fptr)(void); 
fptr test1(void) { 
    void test2(void) { 
     printf("test2\n"); 
    } 
printf("test1\n"); 
return test2; 
} 
int main(void) { 
    void (*f)(void); 
    f = test1(); 
    f(); 
    return 0; 
} 
Problemi correlati