Skip to content

Blocchi di Codice e Funzioni

Pensa a come è scritto un libro: non è un Wall of Text di testo infinito, ma è diviso in capitoli, paragrafi, sezioni. Ogni gruppo di frasi parla di una cosa precisa. Se cerchi un’informazione, sai già in quale capitolo guardare. Il codice funziona allo stesso modo. Le istruzioni non vengono scritte tutte di fila alla rinfusa, ma organizzate in blocchi: gruppi di istruzioni che appartengono insieme e svolgono un compito specifico.


In C++, un blocco di codice è tutto ciò che si trova tra una parentesi graffa aperta { e una chiusa }.

{
  // Tutto quello che è qui dentro
  // fa parte dello stesso blocco
  int x = 5;
  int y = 10;
}

I blocchi possono stare dentro altri blocchi: si parla in questo caso di blocchi padre e blocchi figlio. Un blocco figlio è contenuto all’interno di un blocco padre.

// Blocco padre
{
  int x = 5;
  // Blocco figlio
  {
    int y = 10;
  }
}

📦 Scope: la Visibilità delle Variabili

Section titled “📦 Scope: la Visibilità delle Variabili”

Una variabile dichiarata all’interno di un blocco esiste solo dentro quel blocco e nei suoi figli. Non appena si chiude la parentesi graffa }, la variabile scompare e non è più accessibile. Questo concetto si chiama scope (o visibilità).

{
  int x = 5; // x nasce qui

  {
    int y = 10; // y nasce qui
    Serial.println(x); // ✅ x è visibile: siamo nel suo blocco figlio
    Serial.println(y); // ✅ y è visibile: siamo nel suo blocco
  }
  // y qui non esiste

  Serial.println(x); // ✅ x è ancora visibile
  Serial.println(y); // ❌ ERRORE: y non esiste più fuori dal suo blocco
}
// x qui non esiste

Lo stesso vale per le funzioni: una variabile dichiarata dentro led1() non esiste in led2(), e viceversa.

void led1() {
  int contatore = 0; // contatore esiste solo qui dentro
}

void led2() {
  Serial.println(contatore); // ❌ ERRORE: contatore non esiste qui
}

Se una variabile deve essere accessibile da tutte le funzioni, va dichiarata fuori da tutti i blocchi, in cima al file. Si chiamano variabili globali.

int contatore = 0; // Variabile globale: visibile ovunque

void led1() {
  contatore++; // ✅ Accessibile
}

void led2() {
  Serial.println(contatore); // ✅ Accessibile
}

Una funzione è un blocco di codice a cui viene dato un nome. Invece di riscrivere le stesse istruzioni ogni volta che servono, le si raccoglie in una funzione e la si chiama quando necessario, facendo eseguire il codice contenuto al suo interno solo quando ne abbiamo bisogno.

Pensiamo a una ricetta: una “Pasta al Pomodoro” è un insieme di istruzioni scritte una volta sola. Ogni volta che vuoi fare la pasta, non riscrivi tutti i passaggi: dici semplicemente “faccio la pasta al pomodoro”. La funzione funziona esattamente così.

// Sintassi:
// tipo nomeFunzione() {
//   istruzioni...
// }
void saluta() {
  Serial.println("Ciao!");
  Serial.println("Benvenuto.");
}

La parola void davanti al nome significa che la funzione non restituisce nessun valore; esegue delle azioni e basta, senza un risultato. Lo vedremo meglio più avanti, per ora scriviamo solamente void.

Per eseguire il codice contenuto in una funzione, basta scrivere il suo nome seguito da () e ;.

void loop() {
  saluta(); // Arduino esegue tutto il codice dentro la funzione "saluta"
  saluta(); // Possiamo chiamarla quante volte vogliamo
}

Organizzare il codice in funzioni porta tre vantaggi enormi: 1. Riutilizzo: Scrivi il codice una volta sola e lo chiami quante volte vuoi. 2. Leggibilità: Un loop() fatto così è immediatamente comprensibile:

void loop() {
  leggiSensori();
  aggiornaDisplay();
  controllaAllarmi();
}

3. Manutenzione: Se c’è un errore nel modo in cui si legge un sensore, sai esattamente dove andare a cercarlo: nella funzione leggiSensori(), non in mezzo a centinaia di righe di codice.