Funzione di richiamo in C

Ciao, aspiranti programmatori! Oggi ci immergeremo nel mondo affascinante delle funzioni di richiamo in C. Come il tuo amico insegnante di scienze informatiche del quartiere, sono entusiasta di guidarti attraverso questo concetto. Credimi, una volta che avrai compreso i richiami, ti sembrerà di aver sbloccato una nuova superpotenza nella programmazione!

C - Callback Function

Cos'è una Funzione di Richiamo?

Iniziamo con le basi. Immagina di essere a una festa della pizza (chi non adora la pizza?) e chiedi al tuo amico di chiamarti quando la pizza arriva. Il tuo amico sta essenzialmente eseguendo un richiamo - ti sta richiamando quando si verifica un evento specifico.

In programmazione C, una funzione di richiamo funziona allo stesso modo. È una funzione che passiamo come argomento ad un'altra funzione. Questa altra funzione poi "richiama" (esegue) la funzione passata quando si verifica un certo evento o quando un compito è completato.

Ecco una semplice struttura di una funzione di richiamo:

void funzione_di_richiamo() {
// Corpo della funzione
}

void funzione_principale(void (*richiamo)()) {
// Qualche codice
richiamo();  // Chiamata della funzione di richiamo
// Altro codice
}

int main() {
funzione_principale(funzione_di_richiamo);
return 0;
}

In questo esempio, funzione_di_richiamo è il nostro richiamo. Lo passiamo a funzione_principale, che poi lo chiama a un certo punto durante la sua esecuzione.

Esempio di Funzione di Richiamo in C

Analizziamo un esempio più concreto. Creeremo un semplice programma che utilizza un richiamo per stampare un messaggio dopo che un calcolo è stato completato.

#include <stdio.h>

// La nostra funzione di richiamo
void stampa_risultato(int risultato) {
printf("Il risultato è: %d\n", risultato);
}

// Funzione che esegue un calcolo e chiama il richiamo
void esegui_operazione(int a, int b, void (*richiamo)(int)) {
int somma = a + b;
richiamo(somma);  // Chiama la funzione di richiamo con il risultato
}

int main() {
esegui_operazione(5, 3, stampa_risultato);
return 0;
}

In questo esempio:

  1. Definiamo una funzione di richiamo stampa_risultato che accetta un intero e lo stampa.
  2. La nostra esegui_operazione accetta due interi e un puntatore a funzione come argomenti.
  3. all'interno di esegui_operazione, calcoliamo la somma e poi chiamiamo la funzione di richiamo con questa somma.
  4. In main, chiamiamo esegui_operazione con i nostri numeri e il richiamo stampa_risultato.

Quando esegui questo programma, stamperà: "Il risultato è: 8"

Funzione di Richiamo con Argomenti

I richiami possono anche accettare più argomenti. Espandiamo il nostro esempio precedente per includere più operazioni:

#include <stdio.h>

// Funzione di richiamo con più argomenti
void stampa_operazione(char operazione, int a, int b, int risultato) {
printf("%d %c %d = %d\n", a, operazione, b, risultato);
}

// Funzione che esegue un calcolo e chiama il richiamo
void esegui_operazione(int a, int b, char op, void (*richiamo)(char, int, int, int)) {
int risultato;
switch(op) {
case '+': risultato = a + b; break;
case '-': risultato = a - b; break;
case '*': risultato = a * b; break;
case '/': risultato = a / b; break;
default: printf("Operazione non valida\n"); return;
}
richiamo(op, a, b, risultato);
}

int main() {
esegui_operazione(5, 3, '+', stampa_operazione);
esegui_operazione(10, 4, '-', stampa_operazione);
esegui_operazione(7, 2, '*', stampa_operazione);
esegui_operazione(20, 5, '/', stampa_operazione);
return 0;
}

Questo programma stamperà:

5 + 3 = 8
10 - 4 = 6
7 * 2 = 14
20 / 5 = 4

Qui, il nostro richiamo stampa_operazione accetta quattro argomenti: l'operazione, due operandi e il risultato. Questo ci permette di creare un output più flessibile e informativo.

Tipi di Richiami in C

In C, possiamo classificare i richiami in due principali tipi:

  1. Richiami Sincroni: Questi vengono eseguiti immediatamente dalla funzione a cui sono passati. I nostri esempi precedenti sono richiami sincroni.

  2. Richiami Asincroni: Questi vengono programmati per essere eseguiti successivamente, spesso utilizzati in programmazione event-driven o quando si ha a che fare con operazioni di I/O.

Analizziamo una tabella riassuntiva di questi tipi:

Tipo Descrizione Caso d'uso Esempio
Sincrono Eseguito immediatamente Operazioni semplici, calcoli Il nostro esempio di operazioni aritmetiche
Asincrono Eseguito successivamente Gestione degli eventi, operazioni di I/O Callback per lettura/scrittura di file, gestori di eventi GUI

Ecco un semplice esempio di richiamo asincrono utilizzando i segnali in C:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void funzione_di_richiamo(int signum) {
printf("Ricevuto segnale %d\n", signum);
}

int main() {
signal(SIGALRM, funzione_di_richiamo);
alarm(5);  // Imposta un allarme per 5 secondi

printf("In attesa dell'allarme...\n");
pause();  // Attendere un segnale

return 0;
}

In questo esempio, funzione_di_richiamo è impostata come richiamo asincrono che verrà chiamata quando il segnale SIGALRM viene ricevuto. La funzione alarm(5) imposta un timer di 5 secondi, dopo cui il segnale SIGALRM verrà inviato, innescando il nostro richiamo.

Ecco tutto, ragazzi! Abbiamo viaggiato attraverso il mondo dei richiami in C. Ricorda, i richiami sono come fedeli sidekick nelle tue avventure di programmazione - sono sempre lì quando ne hai bisogno, pronti a entrare in azione. Continua a esercitarti, e presto sarai in grado di utilizzare i richiami come un professionista!

Credits: Image by storyset