Goto
Tags: Avancé
Les fonctions et structures de controle permettent de
structurer et de décrire de manière lisible le fil d’un
programme, contrairement à un goto
, mais il existe des cas
d’usages où l’usage d’un goto
améliore la lisibilité d’un
programme, voire est indispensable.
Contrairement aux appels de fonction qui utilisent un pile d’appels qui peut déborder, un goto ne peut jamais connaitre de stack overflow. Si un algorithme est plus élégant avec des appels récursifs mais présente le risque de débordement de mémoire, stocker les états dans une liste chainée et simuler les appels de fonctions récursifs peut être un paliatif technique.
Instructions
Un goto ne peut être associé qu’à une instruction et non à une expression. Les codes qui suivent ne sont pas valides
int main() {
printf(toto:"texte"); // "texte" est un paramêtre
int a = 42 ? 12 : tata:21; // "21" est une expression et non une instruction
}
Jusqu’au
C23
si on voulait sauter à la fin d’un bloc,
il fallait obligatoirement lui assigner une instruction
vide ;
: typiquement
int main() {
{
goto ici;
int toto;
ici:; // noter l'instruction vide ";"
}
}
Depuis le C23 on peut assigner une destination de saut à une accolade fermante de fin de bloc.
Saut vers des blocs
Si on saute depuis l’exterieur d’un bloc vers l’interieur de celui-ci, l’espace pour les variables du bloc est alloué, mais si la destination de saut est après leur initialisation, elles seront non initialisées, c’est a dire
int main() {
int toto = 12;
int tata = 14;
goto ici;
{
int toto = 24;
int titi = 30;
ici:
int tata = 28;
printf("toto == %d", toto); // valeur indéfinie, non 24
printf("tata == %d", tata); // 28
printf("toto == %d", titi); // valeur indéfinie, non 30
}
printf("toto == %d", toto); // 12
printf("tata == %d", tata); // 14
}
De la même façon dans les instructions switch les variables de bloc ont des valeurs indéfinies selon le lieu d’aterrissage
int main() {
int toto = 12;
int tata = 14;
switch(toto){
int toto = 24;
int tata = 28;
case 12:
printf("toto == %d", toto); // valeur indéfinie, non 24
break;
case 14:
printf("tata == %d", tata); // valeur indéfinie, non 28
break;
default:
toto = 20; // seulement à partir de ce point "toto" a une valeur définie
printf("toto == %d", toto); // 20
}
printf("toto == %d", toto); // 12
printf("tata == %d", tata); // 14
}
int toto = 24;
en C est un sucre syntaxique qui consiste
à écrire en une ligne
int toto;
toto = 24;
Si la machine virtuelle agrandit automatiquement pour nous la pile, assigner des valeurs aux variables de la pile est laissé au programmeur.
C++ : Le c++ n’autorise pas de pouvoir sauter
par dessus l’initialisation de variables au sein
d’un bloc comme nous venons de le voir,
donc si vous écriver une instruction
switch et que vous déclarez des variables à la suite
d’un case
ou n’importe où dans un bloc d’un switch,
vous devrez obligatoirement isoler ces variables dans un bloc.
Sauts inter fonctions
On peut sauter vers et depuis n’importe quel bloc
au sein d’une fonction, mais on ne peut pas sauter vers
d’autres fonctions avec goto
. Une étiquette de saut
a une portée limitée à sa fonction.
int fun1()
{
toto:
{
toto:; // interdit
}
return 0;
}
int fun2()
{
toto: // autorisé , deux fonction peuvent déclarer la même étiquette
return 0;
}
Pour sauter entre deux fonctions, il faut
utiliser
setjmp
et lngjmp
.