muu
A qualcuno sembrerà strano ma in C esiste la possibilità di un salto incondizionato come ad esempio nel linguaggio BASIC dove, nelle versioni più semplici, era l’unico modo per aggiungere l’else all’if, effettuare dei loop o simulare la chiamata a subroutine.
Si può tranquillamente affermare che in un linguaggio completo del goto se ne può fare benissimo a meno, e il suo uso è considerato un errore. Dal punto di vista “stilistico” l’uso del goto potrebbe rendere la lettura del codice abbastanza sgradevole, ma in alcuni (rari) casi comporta dei vantaggi che potremmo voler sfruttare.
Ad esempio se si vuole saltare un intero prezzo di codice ed arrivare direttamente alla fine della funzione nel caso si verifica una certa condizione, allora si può aggiungere un salto piuttosto che includere il blocco di codice seguente tra parentesi graffe.
int AvoidBrackets(int n)
{
/*
a lot of code
*/
if (n == 0)
goto end;
/*
a lot of code
...
*/
end:
return 0;
}
Il comando goto comporta che l’esecuzione continuerà a partire dall’istruzione con l’etichetta corrispondente. Questa soluzione permette di gestire in maniera veloce il flusso del codice ma è assolutamente evitare. Usare tali accorgimenti in maniera sistematica rende il codice illeggibile e non manutenibile, ma nello scenario di dover risolvere velocemente un problema bloccante in ambienti di produzione, dove magari vigono delle penali in base tempo impiegato per concludere l’operazione di fix, allora tutto è permesso, anche una soluzione sporca ma veloce, purché funzionante; in un secondo momento ci si preoccuperà ci correggere lo stile.
Supponiamo di dover individuare quattro numeri interi x, y, z e t per i quali la somma dei quadrati dei primi tre sia uguale al quadrato del quarto, in formule è necessario che si verifichi la condizione (x * x + y * y + z * z == t * t); la procedura si fermerà alla prima combinazione che verifica la condizione.
Una soluzione formalmente corretta potrebbe essere questa: si utilizza una variabile logica allo scopo di uscire da tutti i loop innestati non appena la condizione è verificata.
int FindValues(int limit)
{
int found = 0;
int x, y, z, t;
for (x = 2; x <= limit && found == 0; x++) {
for (y = x + 1; y <= limit && found == 0; y++) {
for (z = y + 2; z <= limit && found == 0; z++) {
for (t = 2; t <= limit && found == 0; t++) {
if (x * x + y * y + z * z == t * t) {
printf("%d*%d+%d*%d+%d*%d=%d\n", x, x, y, y, z, z, x*x+y*y+z*z);
printf("%d*%d=%d\n", t, t, t * t);
found = 1;
}
}
}
}
}
return found;
}
Ma come si può resistere ad aggiungere semplicemente un goto all’interno del loop puntando alla fine della funzione?
int FindValues(int limit)
{
int found = 0;
int x, y, z, t;
for (x = 2; x <= limit; x++) {
for (y = x + 1; y <= limit; y++) {
for (z = y + 2; z <= limit; z++) {
for (t = 2; t <= limit; t++) {
if (x * x + y * y + z * z == t * t) {
printf("%d*%d+%d*%d+%d*%d=%d\n", x, x, y, y, z, z, x*x+y*y+z*z);
printf("%d*%d=%d\n", t, t, t * t);
found = 1;
goto end;
}
}
}
}
}
end:
return found;
}
Ciò dimostra che, se il salto incondizionato è usato con parsimonia e attenzione, in contesti che ne giustificano la presenza, non è da considerarsi un errore.