Passando il puntatore funzione

Sono un po ‘confuso su come passare un puntatore a una funzione puntatore. Ho una funzione che accetta un puntatore a una funzione che capisco senza problemi (ExecBlock). Ma mi viene dato un altro prototipo di una funzione (ExecBlock2) che prende il puntatore dereferenziato (non sono sicuro di cosa sia esattamente) e accetta anche l’argomento se la funzione passata ne ha. Se qualcuno potesse spiegare la precedenza e esattamente quale dereferenziazione farebbe una funzione puntatore. Non è solo il passaggio della funzione stessa? Cosa fa (void *) in questo caso?

int ExecBlock (void (*f) (void), int isSet) { return ExecBlock2( HOW TO PASS HERE? , NULL, isSet); } int ExecBlock2(void *(*f)(void *), void *arg, int isSet) { ... more code } 

Grazie!

 void (*f) (void) 

significa puntatore per funzionare senza argomenti che restituiscono nulla.

 void *(*f)(void *) 

significa puntatore a funzionare prendendo un puntatore vuoto e restituendo un puntatore vuoto.

Dato che i tipi sono diversi, il compilatore non ti permetterà di passare l’uno all’altro senza lanciare. (Nota che il cast non è la risposta giusta qui, e come sottolinea @detly, si traduce in un comportamento indefinito).

Per quanto riguarda i puntatori di dereferenziamento alle funzioni, non è necessario inserire esplicitamente un “*” prima di un puntatore alla funzione per chiamarlo. Ad esempio, puoi chiamare il tuo puntatore funzione f solo facendo

 f(); 

Un esempio di puntatore di funzione

Supponiamo che tu abbia una funzione f , che vorresti passare ad una funzione chiamata takes_a_function . takes_a_function avrà probabilmente un tipo simile

 void takes_a_function(void (*f)(void *data), void *data); 

Notate come ci sono due argomenti su takes_a_function , un puntatore a funzione e un puntatore vuoto ad alcuni dati. Si noti inoltre che la funzione f capita di prendere un puntatore vuoto come argomento. L’idea è che puoi passare i dati a takes_a_function , e lo passerà a f . Ad esempio, takes_a_function potrebbe essere definito come

 void takes_a_function(void (*f)(void *), void *data) { f(data); } 

Ora, scriviamo una funzione da passare a takes_a_function . La nostra funzione stamperà solo un int che viene passato ad esso.

 void prints_an_int(void *data) { // The idiom for converting a void pointer to another kind // of pointer. NO NEED TO CAST. Note this behavior is only // defined if the pointer data really does point to an int. int *i = data; printf("%d", *i); } int i = 0; takes_a_function(prints_an_int, &i); 

Un paio di punti chiave su questo esempio:

  • prints_an_int ha lo stesso tipo del puntatore di funzione previsto da takes_a_function . Non c’è bisogno di lanciare.
  • Non è necessario utilizzare l’operatore & per creare un riferimento a una funzione. Questo è il motivo per cui possiamo passare direttamente prints_an_int a takes_a_function . Ma potremmo anche dire takes_a_function(&prints_an_int, &i) , e sarebbe lo stesso.
  • void* significa fondamentalmente “puntatore a tipo sconosciuto”. Per fare effettivamente qualcosa con esso, è necessario assegnare una variabile di tipo void* a un’altra variabile puntatore di cui si aspetta il tipo. Questo è garantito per funzionare solo se si passa effettivamente il tipo di puntatore corretto! In questo esempio, possiamo assegnare data a un int* , poiché i dati puntano davvero a un int. Se vuoi più dati di un semplice numero intero, un modello comune è quello di creare il tuo tipo di struct che include tutti i campi che vuoi e passarlo invece.
  • Come caso speciale, il compilatore non richiede di eseguire il cast quando si assegnano i puntatori void ad altri puntatori e viceversa. Ma di nuovo, si ottiene un comportamento definito solo se alla fine si converte un puntatore void nel tipo corretto.

Ad esempio hai una funzione

 void * abc(void *) { //... } 

 int ExecBlock (void (*f) (void), int isSet) { return ExecBlock2( abc , NULL, isSet); //use name of the function which have void * as parameter type list and return type void * } int ExecBlock2(void *(*f)(void *), void *arg, int isSet) { ... more code } 

Vedi i puntatori di funzione