Goto - STB1019/SkullOfSummer GitHub Wiki

GOTO Statement

L'istruzione goto corrisponde ad un salto incondizionato, letteralmente è il trasferimento diretto a un'altra riga del codice, a differenza di una normale chiamata a funzione che una volta svolto il suo compito ritorna al flow originale. La sintassi di utilizzo nel linguaggio C è:

...
ETICHETTA:
//Codice marcato dall'etichetta
...
goto ETICHETTA;

Vi sono varie ragioni per cui l'uso del goto è sconsigliato o addirittura considerato bad practice:

  1. Non limita lo scope, ad esempio in codice mal strutturato è possibile saltare dichiarazioni o condizioni;
  2. Il codice risultante potrebbe essere considerato difficile da interpretare o addirittura illeggibile;
  3. Ogni blocco di codice comprendente goto ha il suo equivalente ciclico(cfr. Teorema di Jacopini e Programmazione Strutturata);

L'istruzione goto non altera in alcun modo il codice scritto, serve solo a variare il flow del programma. Le label servono soltanto all'istruzione goto: in tutti gli altri casi vengono saltate a priori.

Break programmatico di fitti cicli annidati

L'utilizzo di questa istruzione è consigliata quando si vuole uscire da una lunga serie di cicli annidati

for ...
 for ...
  if(breakout_condition) 
   goto final;
final:

Dato che non esiste un modo lineare di uscire da questo tipo di costrutti(se non quello di finirli tutti, ma chiaramente dipende dal problema implementato).

Throwing di errori

In generale, come già detto, se sembra un ciclo while, usa un while..., tuttavia goto può essere utile anche per implementare costrutti non presenti nativamente in C, come l'esempio sopra oppure il try-catch tanto caro ai programmatori Java. L'esempio sotto mostra la logica di implementazione di un sistema di gestione degli errori nel proprio programma

void foo()
{
 if (!doA())
  goto exit;
 if (!doB())
  goto cleanupA;
 if (!doC())
  goto cleanupB;

/* everything has succeeded */

 cleanupB:
  undoB();
 cleanupA:
  undoA();
 exit:
  return;
}

Esempi di bad practice

if(condizione1)
 goto LABEL1;
if(condizione2)
 goto LABEL2;

Questo tipo di codice è palesemente sostituibile con uno switch

START:
 ...
 goto FUNC1;
...
FUNC1:
 goto START;
...

Sebbene a prima vista questa tipologia di errore possa sembrare poco probabile, l'utilizzo di goto(e il conseguente cambio di paradigma) lo rende tanto probabile quanto un errore di sintassi; l'equivalente ciclico dell'esempio sopra è il classico for infinito for(;;){}

Conclusioni

Indipendentemente dalle preferenze del vostro professore(o capo), l'uso di goto o di qualsiasi altra istruzione è strettamente dipendente dai due requisiti fondamentali della programmazione: buon senso e leggibilità a lungo termine. Può essere utile scrivere in prima persona programmi di esempio in cui blocchi di codice vengono saltati, oppure ritornano risultati non aspettati, per vedere come effettivamente l'istruzione goto sia più simile a una direttiva al preprocessore che a una "normale" istruzione:

Fonti

Libro: Kim&King Programmazione C(varie);

Domande da StackOverflow:

https://stackoverflow.com/questions/245742/examples-of-good-gotos-in-c-or-c;

https://softwareengineering.stackexchange.com/questions/154974/is-this-a-decent-use-case-for-goto-in-c;

Programmazione Strutturata con goto:

http://sbel.wisc.edu/Courses/ME964/Literature/knuthProgramming1974.pdf;