Il y a quelques raisons d'utiliser l'énoncé "goto" que je connais (certains en ont déjà parlé):
Quitter proprement une fonction
Souvent, dans une fonction, vous pouvez allouer des ressources et devez quitter à plusieurs endroits. Les programmeurs peuvent simplifier leur code en plaçant le code de nettoyage des ressources à la fin de la fonction, et tous les "points de sortie" de la fonction se trouveront sur l'étiquette de nettoyage. De cette façon, vous n'avez pas à écrire de code de nettoyage à chaque "point de sortie" de la fonction.
Quitter les boucles imbriquées
Si vous êtes dans une boucle imbriquée et devez rompre toutes les boucles, un goto peut rendre cela beaucoup plus propre et plus simple que les instructions break et les if-checks.
Améliorations des performances de bas niveau
Ceci n'est valable que dans le code critique, mais les instructions goto s'exécutent très rapidement et peuvent vous donner un coup de pouce lors du déplacement dans une fonction. Il s'agit cependant d'une arme à double tranchant, car un compilateur ne peut généralement pas optimiser le code contenant des gotos.
Notez que dans tous ces exemples, les gotos sont limités à la portée d'une seule fonction.
goto
parreturn
est tout simplement stupide. Ce n'est pas "refactoriser" quoi que ce soit, c'est juste "renommer" pour que les personnes qui ont grandi dans ungoto
environnement sans répression (c'est-à-dire nous tous) se sentent mieux à l'idée d'utiliser ce qui équivaut moralement à ungoto
. Je préfère de loin voir la boucle là où je l'utilise et en voir un peugoto
, qui en soi n'est qu'un outil , que de voir quelqu'un ayant déplacé la boucle quelque part sans rapport juste pour éviter ungoto
.break
,continue
dans lereturn
fondgoto
, sont simplement dans un bel emballage.do{....}while(0)
est censé être une meilleure idée que goto, sauf pour le fait que cela fonctionne en Java.Toute personne qui s'oppose
goto
, directement ou indirectement, à l'article GoTo Considered Harmful d' Edsger Dijkstra pour justifier sa position. Dommage que l'article de Dijkstra n'ait pratiquement rien à voir avec la façon dont lesgoto
instructions sont utilisées de nos jours et que ce que dit l'article n'a donc pas ou peu d'application sur la scène de la programmation moderne. legoto
mème -less confine maintenant sur une religion, jusque dans ses écritures dictées d'en haut, ses grands prêtres et l'évitement (ou pire) des hérétiques perçus.Mettons le document de Dijkstra en contexte pour éclairer un peu le sujet.
Lorsque Dijkstra a écrit son article, les langues populaires de l'époque étaient des langues procédurales non structurées comme BASIC, FORTRAN (les anciens dialectes) et diverses langues d'assemblage. Il était assez courant que les personnes utilisant les langages de niveau supérieur sautent sur toute leur base de code dans des fils d'exécution tordus et déformés qui ont donné naissance au terme "code spaghetti". Vous pouvez le voir en passant au jeu Trek classique écrit par Mike Mayfield et en essayant de comprendre comment les choses fonctionnent. Prenez quelques instants pour regarder cela.
CECI est «l'utilisation effrénée de la déclaration« aller à »contre laquelle Dijkstra se penchait dans son journal en 1968. CECI est l'environnement dans lequel il vivait qui l'a amené à écrire ce journal. La possibilité de sauter où vous voulez dans votre code à tout moment que vous aimiez était ce qu'il critiquait et exigeait d'être arrêté. La comparaison avec les pouvoirs anémiques de
goto
C ou d'autres langages plus modernes est tout simplement risible.J'entends déjà les chants élevés des cultistes face à l'hérétique. "Mais," scandent-ils, "vous pouvez rendre le code très difficile à lire avec
goto
en C." Oh oui? Vous pouvez également rendre le code très difficile à lire sansgoto
. Comme celui-ci:Pas un
goto
en vue, donc il doit être facile à lire, non? Ou que diriez-vous de celui-ci:Non
goto
non plus. Il doit donc être lisible.Quel est mon point avec ces exemples? Ce ne sont pas les fonctionnalités de langage qui rendent le code illisible et non maintenable. Ce n'est pas la syntaxe qui le fait. Ce sont les mauvais programmeurs qui causent cela. Et mauvais programmeurs, comme vous pouvez le voir dans cet article ci - dessus, peuvent faire une fonctionnalité de langage illisible et inutilisable. Comme les
for
boucles là-haut. (Vous pouvez les voir, non?)Maintenant, pour être juste, certaines constructions de langage sont plus faciles à abuser que d'autres. Si vous êtes un programmeur C, cependant, je regarderais de plus près environ 50% des utilisations
#define
bien avant de partir en croisadegoto
!Donc, pour ceux qui ont pris la peine de lire jusqu'ici, il y a plusieurs points clés à noter.
goto
déclarations a été écrit pour un environnement de programmation oùgoto
était un beaucoup plus de dégâts potentiels que dans la plupart des langages modernes qui ne sont pas assembleurs.goto
cause de cela est aussi rationnel que de dire "J'ai essayé de m'amuser une fois mais je ne l'aimais pas alors maintenant je suis contre".goto
déclarations dans le code qui ne peuvent pas être remplacées de manière adéquate par d'autres constructions.godo
abomination " " où unedo
boucle toujours fausse est rompuebreak
à la place de agoto
. Ce sont souvent pires que l'utilisation judicieuse degoto
.la source
goto
ce qui est réellement (c'est la question posée)Obéir aveuglément aux meilleures pratiques n'est pas une meilleure pratique. L'idée d'éviter les
goto
instructions comme forme principale de contrôle de flux est d'éviter de produire du code spaghetti illisible. S'ils sont utilisés avec parcimonie aux bons endroits, ils peuvent parfois être le moyen le plus simple et le plus clair d'exprimer une idée. Walter Bright, le créateur du compilateur Zortech C ++ et du langage de programmation D, les utilise fréquemment, mais judicieusement. Même avec lesgoto
déclarations, son code est toujours parfaitement lisible.Bottom line: Éviter
goto
pour évitergoto
est inutile. Ce que vous voulez vraiment éviter, c'est produire du code illisible. Si votregoto
code -laden est lisible, il n'y a rien de mal à cela.la source
Étant donné
goto
que le raisonnement sur le déroulement du programme est difficile 1 (alias «code spaghetti»), ilgoto
n'est généralement utilisé que pour compenser les fonctionnalités manquantes: l'utilisation degoto
peut effectivement être acceptable, mais uniquement si le langage n'offre pas de variante plus structurée à obtenir. le même objectif. Prenons l'exemple de Doubt:C'est vrai - mais seulement si le langage ne permet pas la gestion structurée des exceptions avec du code de nettoyage (comme RAII ou
finally
), qui fait le même travail mieux (car il est spécialement conçu pour le faire), ou quand il y a une bonne raison de ne pas d'utiliser une gestion structurée des exceptions (mais vous n'aurez jamais ce cas, sauf à un niveau très bas).Dans la plupart des autres langues, la seule utilisation acceptable de
goto
est de quitter les boucles imbriquées. Et même là, il est presque toujours préférable de soulever la boucle extérieure dans une méthode propre et de l'utiliser à lareturn
place.Autre que cela,
goto
est un signe que pas assez de réflexion est allée dans le morceau de code particulier.1 Les langages modernes qui prennent
goto
en charge implémentent certaines restrictions (par exemple,goto
ne peuvent pas entrer ou sortir des fonctions) mais le problème reste fondamentalement le même.Soit dit en passant, il en va de même, bien entendu, pour les autres fonctionnalités linguistiques, notamment les exceptions. Et il existe généralement des règles strictes pour utiliser ces fonctionnalités uniquement lorsque cela est indiqué, comme la règle de ne pas utiliser d'exceptions pour contrôler le flux de programme non exceptionnel.
la source
finally
? Donc, utiliser des exceptions pour d'autres choses que la gestion des erreurs est une bonne chose, mais unegoto
mauvaise utilisation? Je pense que les exceptions portent bien leur nom.Eh bien, il y a une chose qui est toujours pire que
goto's
; utilisation étrange d'autres opérateurs de flux de programme pour éviter un goto:Exemples:
la source
do{}while(false)
Je pense que cela peut être considéré comme idiomatique. Vous n'êtes pas autorisé à être en désaccord: Dgoto after_do_block;
sans vraiment le dire. Sinon ... une "boucle" qui s'exécute exactement une fois? J'appellerais cela un abus des structures de contrôle.#define
y en a beaucoup, plusieurs fois bien pire que de l'utiliser degoto
temps en temps: DEn C # commutateur déclaration doest permettent pas fall-through . Donc, goto est utilisé pour transférer le contrôle vers une étiquette de boîtier de commutation spécifique ou l' étiquette par défaut .
Par exemple:
Edit: Il y a une exception à la règle "pas d'interruption". La reprise est autorisée si une instruction case n'a pas de code.
la source
goto case 5:
quand vous êtes dans le cas 1). Il semble que la réponse de Konrad Rudolph soit correcte ici:goto
compense une fonctionnalité manquante (et est moins claire que la fonctionnalité réelle ne le serait). Si ce que nous voulons vraiment, c'est une solution de traversée, le meilleur défaut serait peut-être la non-transition, mais quelque chose commecontinue
la demander explicitement.#ifdef TONGUE_IN_CHEEK
Perl a un
goto
qui vous permet d'implémenter les appels de queue du pauvre. :-P#endif
D' accord, donc cela n'a rien à voir avec C de
goto
. Plus sérieusement, je suis d'accord avec les autres commentaires sur l'utilisationgoto
pour les nettoyages, ou pour implémenter l'appareil de Duff , ou similaire. Il s'agit d'utiliser, pas d'abuser.(Le même commentaire peut s'appliquer aux
longjmp
exceptionscall/cc
et similaires --- elles ont des utilisations légitimes, mais peuvent facilement être utilisées à mauvais escient. Par exemple, lever une exception uniquement pour échapper à une structure de contrôle profondément imbriquée, dans des circonstances totalement non exceptionnelles .)la source
J'ai écrit plus de quelques lignes de langage d'assemblage au fil des ans. En fin de compte, chaque langage de haut niveau se compile en gotos. D'accord, appelez-les "branches" ou "sauts" ou quoi que ce soit d'autre, mais ce sont des gotos. Quelqu'un peut-il écrire un assembleur goto-less?
Maintenant, bien sûr, vous pouvez signaler à un programmeur Fortran, C ou BASIC que lancer une émeute avec des gotos est une recette de spaghetti bolognaise. La réponse n'est cependant pas de les éviter, mais de les utiliser avec précaution.
Un couteau peut être utilisé pour préparer de la nourriture, libérer quelqu'un ou tuer quelqu'un. Faisons-nous sans couteaux par peur de ces derniers? De même le goto: utilisé avec négligence, il gêne, utilisé avec précaution, il aide.
la source
Jetez un œil à Quand utiliser Goto lors de la programmation en C :
Qu'est ce que je veux dire? Vous pourriez avoir un code qui ressemble à ceci:
C'est très bien jusqu'à ce que vous réalisiez que vous devez changer votre code de nettoyage. Ensuite, vous devez passer par et apporter 4 modifications. Maintenant, vous pourriez décider que vous pouvez simplement encapsuler tout le nettoyage dans une seule fonction; ce n'est pas une mauvaise idée. Mais cela signifie que vous devrez faire attention aux pointeurs - si vous prévoyez de libérer un pointeur dans votre fonction de nettoyage, il n'y a aucun moyen de le définir pour pointer sur NULL à moins que vous ne passiez un pointeur sur un pointeur. Dans de nombreux cas, vous n'utiliserez plus ce pointeur de toute façon, ce qui peut ne pas être une préoccupation majeure. D'un autre côté, si vous ajoutez un nouveau pointeur, un nouveau descripteur de fichier ou une autre chose qui nécessite un nettoyage, vous devrez à nouveau modifier votre fonction de nettoyage; puis vous devrez modifier les arguments de cette fonction.
En utilisant
goto
, il seraL'avantage ici est que votre code suivant la fin a accès à tout ce dont il aura besoin pour effectuer le nettoyage, et vous avez réussi à réduire considérablement le nombre de points de changement. Un autre avantage est que vous êtes passé de plusieurs points de sortie pour votre fonction à un seul; il n'y a aucune chance que vous reveniez accidentellement de la fonction sans nettoyer.
De plus, puisque goto n'est utilisé que pour sauter à un seul point, ce n'est pas comme si vous créez une masse de code spaghetti qui va et vient dans le but de simuler des appels de fonction. Au contraire, goto aide en fait à écrire du code plus structuré.
En un mot,
goto
devrait toujours être utilisé avec parcimonie et en dernier recours - mais il y a un temps et un lieu pour cela. La question ne devrait pas être "devez-vous l'utiliser" mais "est-ce le meilleur choix" pour l'utiliser.la source
Une des raisons pour lesquelles goto est mauvais, outre le style de codage, c'est que vous pouvez l'utiliser pour créer des boucles superposées mais non imbriquées :
Cela créerait une structure de contrôle de flux bizarre, mais peut-être légale, où une séquence comme (a, b, c, b, a, b, a, b, ...) est possible, ce qui rend les pirates du compilateur mécontents. Apparemment, il existe un certain nombre de astuces d'optimisation intelligentes qui reposent sur ce type de structure qui ne se produit pas. (Je devrais vérifier ma copie du livre du dragon ...) Le résultat de ceci pourrait (en utilisant certains compilateurs) être que d'autres optimisations ne sont pas faites pour le code qui contient
goto
s.Cela peut être utile si vous le savez , "oh, au fait", arrive à persuader le compilateur d'émettre du code plus rapidement. Personnellement, je préfère essayer d'expliquer au compilateur ce qui est probable et ce qui ne l'est pas avant d'utiliser une astuce comme goto, mais sans doute, je pourrais aussi essayer
goto
avant de pirater l'assembleur.la source
goto
est utile, c'est qu'elle vous permet de construire des boucles comme celle-ci, ce qui nécessiterait un tas de contorsions logiques sinon. Je dirais en outre que si l'optimiseur ne sait pas comment réécrire cela, alors c'est bien . Une boucle comme celle-ci ne devrait pas être effectuée pour des performances ou une lisibilité, mais parce que c'est exactement l'ordre dans lequel les choses doivent se produire. Dans ce cas, je ne voudrais pas particulièrement que l'optimiseur tourne avec.Je trouve drôle que certaines personnes iront jusqu'à donner une liste de cas où goto est acceptable, en disant que toutes les autres utilisations sont inacceptables. Pensez-vous vraiment que vous connaissez tous les cas où goto est le meilleur choix pour exprimer un algorithme?
Pour illustrer, je vais vous donner un exemple que personne ici n'a encore montré:
Aujourd'hui, j'écrivais du code pour insérer un élément dans une table de hachage. La table de hachage est un cache des calculs précédents qui peuvent être écrasés à volonté (affectant les performances mais pas l'exactitude).
Chaque compartiment de la table de hachage a 4 emplacements, et j'ai un tas de critères pour décider quel élément remplacer par un compartiment plein. À l'heure actuelle, cela signifie effectuer jusqu'à trois passages dans un seau, comme ceci:
Maintenant, si je n'utilisais pas goto, à quoi ressemblerait ce code?
Quelque chose comme ça:
Il semblerait de pire en pire si plus de passes sont ajoutées, tandis que la version avec goto conserve le même niveau d'indentation à tout moment et évite l'utilisation d'instructions if parasites dont le résultat est impliqué par l'exécution de la boucle précédente.
Il y a donc un autre cas où goto rend le code plus propre et plus facile à écrire et à comprendre ... Je suis sûr qu'il y en a beaucoup plus, alors ne faites pas semblant de connaître tous les cas où goto est utile, en dissipant les bons que vous ne pourriez pas n'y pense pas.
la source
goto
avoir que chaque fonction soit au même niveau d'abstraction. Cela évitegoto
est un bonus.container::iterator it = slot_p.find(hash_key); if (it != slot_p.end()) it->overwrite(hash_key); else it = slot_p.find_first_empty();
je trouve ce type de programmation beaucoup plus facile à lire. Dans ce cas, chaque fonction peut être écrite comme une fonction pure, ce qui est beaucoup plus facile à raisonner. La fonction principale explique maintenant ce que fait le code uniquement par le nom des fonctions, puis si vous le souhaitez, vous pouvez consulter leurs définitions pour savoir comment il le fait.La règle avec goto que nous utilisons est que goto est correct pour passer à un point de nettoyage de sortie unique dans une fonction. Dans les fonctions vraiment complexes, nous assouplissons cette règle pour permettre aux autres sauts en avant. Dans les deux cas, nous évitons les instructions si profondément imbriquées qui se produisent souvent lors de la vérification du code d'erreur, ce qui améliore la lisibilité et la maintenance.
la source
La discussion la plus réfléchie et approfondie des instructions goto, de leurs utilisations légitimes et des constructions alternatives qui peuvent être utilisées à la place des "instructions goto vertueuses" mais peuvent être utilisées aussi facilement que les instructions goto, est l'article de Donald Knuth " Programmation structurée avec des instructions goto " , dans les Computing Surveys de décembre 1974 (volume 6, n ° 4. pp. 261 - 301).
Il n'est pas surprenant que certains aspects de ce document de 39 ans soient datés: des augmentations de l'ordre de grandeur de la puissance de traitement rendent certaines des améliorations de performances de Knuth imperceptibles pour des problèmes de taille moyenne, et de nouvelles constructions de langage de programmation ont été inventées depuis. (Par exemple, les blocs try-catch subsument la construction de Zahn, bien qu'ils soient rarement utilisés de cette façon.) Mais Knuth couvre tous les côtés de l'argument, et devrait être lu avant que quiconque ne ressasse le problème.
la source
Dans un module Perl, vous souhaitez parfois créer des sous-programmes ou des fermetures à la volée. Le fait est qu'une fois que vous avez créé le sous-programme, comment y accéder. Vous pouvez simplement l'appeler, mais si le sous-programme l'utilise,
caller()
il ne sera pas aussi utile qu'il pourrait l'être. C'est là que lagoto &subroutine
variation peut être utile.Voici un petit exemple:
Vous pouvez également utiliser cette forme de
goto
pour fournir une forme rudimentaire d'optimisation des appels de queue.(Dans Perl 5 version 16, ce serait mieux écrit comme
goto __SUB__;
)Il y a un module qui importera un
tail
modificateur et un qui importerarecur
si vous n'aimez pas utiliser cette forme degoto
.La plupart des autres raisons d'utiliser
goto
sont mieux faites avec d'autres mots clés.Comme
redo
un peu de code:Ou en allant à
last
un peu de code à partir de plusieurs endroits:la source
C n'a pas de rupture à plusieurs niveaux / étiquetée, et tous les flux de contrôle ne peuvent pas être facilement modélisés avec les primitives d'itération et de décision de C. les gotos contribuent grandement à corriger ces défauts.
Parfois, il est plus clair d'utiliser une variable d'indicateur d'une sorte pour effectuer une sorte de coupure pseudo-multi-niveaux, mais elle n'est pas toujours supérieure au goto (au moins un goto permet de déterminer facilement où va le contrôle, contrairement à une variable d'indicateur ), et parfois vous ne voulez tout simplement pas payer le prix de performance des drapeaux / autres contorsions pour éviter le goto.
libavcodec est un morceau de code sensible aux performances. L'expression directe du flux de contrôle est probablement une priorité, car elle aura tendance à mieux fonctionner.
la source
Tout aussi bien personne n'a jamais mis en œuvre la déclaration "COME FROM" ....
la source
Je trouve le do {} tout en (faux) usage tout à fait révoltant. Il est concevable pourrait me convaincre qu'il est nécessaire dans certains cas étranges, mais jamais qu'il s'agit d'un code propre et sensible.
Si vous devez faire une telle boucle, pourquoi ne pas rendre explicite la dépendance à la variable indicateur?
la source
/*empty*/
passtepfailed = 1
? En tout cas, comment est-ce mieux qu'undo{}while(0)
? Dans les deux, vous devez enbreak
sortir (ou dans le vôtrestepfailed = 1; continue;
). Cela me semble inutile.1) L'utilisation la plus courante de goto que je connaisse est l'émulation de la gestion des exceptions dans les langages qui ne l'offrent pas, à savoir en C. (Le code donné par Nuclear ci-dessus est juste cela.) Regardez le code source Linux et vous ' Je verrai un bazillion de gotos utilisés de cette façon; il y avait environ 100 000 gotos dans le code Linux selon une enquête rapide menée en 2013: http://blog.regehr.org/archives/894 . L'utilisation de Goto est même mentionnée dans le guide de style de codage Linux: https://www.kernel.org/doc/Documentation/CodingStyle . Tout comme la programmation orientée objet est émulée à l'aide de structures peuplées de pointeurs de fonction, goto a sa place dans la programmation C. Alors, qui a raison: Dijkstra ou Linus (et tous les codeurs du noyau Linux)? C'est de la théorie contre la pratique.
Il y a cependant le piège habituel de ne pas avoir de support au niveau du compilateur et de vérifier les constructions / modèles courants: il est plus facile de les mal utiliser et d'introduire des bogues sans vérifications au moment de la compilation. Windows et Visual C ++ mais en mode C offrent une gestion des exceptions via SEH / VEH pour cette raison: les exceptions sont utiles même en dehors des langages OOP, c'est-à-dire dans un langage procédural. Mais le compilateur ne peut pas toujours sauvegarder votre bacon, même s'il offre un support syntaxique pour les exceptions dans le langage. Prenons comme exemple de ce dernier cas le fameux bogue Apple SSL "goto fail", qui vient de dupliquer un goto avec des conséquences désastreuses ( https://www.imperialviolet.org/2014/02/22/applebug.html ):
Vous pouvez avoir exactement le même bogue en utilisant des exceptions prises en charge par le compilateur, par exemple en C ++:
Mais les deux variantes du bogue peuvent être évitées si le compilateur analyse et vous avertit du code inaccessible. Par exemple, la compilation avec Visual C ++ au niveau d'avertissement / W4 trouve le bogue dans les deux cas. Java, par exemple, interdit le code inaccessible (où il peut le trouver!) Pour une assez bonne raison: il s'agit probablement d'un bogue dans le code moyen de Joe. Tant que la construction goto ne permet pas aux cibles que le compilateur ne peut pas facilement comprendre, comme les gotos aux adresses calculées (**), il n'est pas plus difficile pour le compilateur de trouver du code inaccessible dans une fonction avec gotos que d'utiliser Dijkstra - code approuvé.
(**) Note de bas de page: Les gotos vers les numéros de ligne calculés sont possibles dans certaines versions de Basic, par exemple GOTO 10 * x où x est une variable. De façon assez confuse, dans Fortran, "goto calculé" fait référence à une construction qui est équivalente à une instruction switch en C. La norme C n'autorise pas les gotos calculés dans le langage, mais seulement les gotos aux étiquettes déclarées statiquement / syntaxiquement. GNU C a cependant une extension pour obtenir l'adresse d'une étiquette (l'opérateur unaire, préfixe &&) et permet également d'accéder à une variable de type void *. Voir https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html pour en savoir plus sur ce sous-sujet obscur. Le reste de ce post ne concerne pas cette obscure fonctionnalité GNU C.
Les gotos C standard (c'est-à-dire non calculés) ne sont généralement pas la raison pour laquelle le code inaccessible ne peut pas être trouvé au moment de la compilation. La raison habituelle est un code logique comme le suivant. Donné
Il est tout aussi difficile pour un compilateur de trouver du code inaccessible dans l'une des 3 constructions suivantes:
(Excusez mon style de codage lié à l'accolade, mais j'ai essayé de garder les exemples aussi compacts que possible.)
Visual C ++ / W4 (même avec / Ox) ne parvient pas à trouver de code inaccessible dans aucun d'entre eux, et comme vous le savez probablement, le problème de la recherche de code inaccessible est en général indécidable. (Si vous ne me croyez pas à ce sujet: https://www.cl.cam.ac.uk/teaching/2006/OptComp/slides/lecture02.pdf )
Comme problème connexe, le goto C peut être utilisé pour émuler des exceptions uniquement à l'intérieur du corps d'une fonction. La bibliothèque C standard offre une paire de fonctions setjmp () et longjmp () pour émuler des sorties / exceptions non locales, mais celles-ci présentent de sérieux inconvénients par rapport à ce que d'autres langues offrent. L'article Wikipedia http://en.wikipedia.org/wiki/Setjmp.h explique assez bien ce dernier problème. Cette paire de fonctions fonctionne également sous Windows ( http://msdn.microsoft.com/en-us/library/yz2ez4as.aspx ), mais presque personne ne les utilise là-bas car SEH / VEH est supérieur. Même sous Unix, je pense que setjmp et longjmp sont très rarement utilisés.
2) Je pense que la deuxième utilisation la plus courante de goto en C consiste à implémenter une interruption à plusieurs niveaux ou une poursuite à plusieurs niveaux, ce qui est également un cas d'utilisation assez peu controversé. Rappelez-vous que Java n'autorise pas le goto label, mais autorise break label ou continue label. Selon http://www.oracle.com/technetwork/java/simple-142616.html , il s'agit en fait du cas d'utilisation le plus courant des gotos en C (90% disent-ils), mais selon mon expérience subjective, le code système tend à d'utiliser gotos pour la gestion des erreurs plus souvent. Peut-être dans le code scientifique ou lorsque le système d'exploitation offre une gestion des exceptions (Windows), alors les sorties à plusieurs niveaux sont le cas d'utilisation dominant. Ils ne donnent pas vraiment de détails sur le contexte de leur enquête.
Modifié pour ajouter: il s'avère que ces deux modèles d'utilisation se trouvent dans le livre C de Kernighan et Ritchie, vers la page 60 (selon l'édition). Une autre chose à noter est que les deux cas d'utilisation impliquent uniquement des gotos avancés. Et il s'avère que l'édition MISRA C 2012 (contrairement à l'édition 2004) autorise désormais les gotos, tant qu'ils ne sont que des versions avancées.
la source
Certains disent qu'il n'y a pas de raison pour goto en C ++. Certains disent que dans 99% des cas, il existe de meilleures alternatives. Ce n'est pas du raisonnement, juste des impressions irrationnelles. Voici un exemple solide où goto mène à un joli code, quelque chose comme une boucle do-while améliorée:
Comparez-le au code gratuit:
Je vois ces différences:
{}
bloc imbriqué est nécessaire (bien qu'ildo {...} while
semble plus familier)loop
variable supplémentaire est nécessaire, utilisée à quatre endroitsloop
loop
ne contient aucune donnée, il contrôle simplement le flux de l'exécution, ce qui est moins compréhensible qu'une simple étiquetteIl y a un autre exemple
Maintenant, débarrassons-nous du goto "diabolique":
Vous voyez que c'est le même type d'utilisation de goto, c'est un modèle bien structuré et ce n'est pas un goto en avant autant promu que la seule façon recommandée. Vous voulez sûrement éviter un code "intelligent" comme celui-ci:
Le fait est que goto peut être facilement utilisé à mauvais escient, mais goto lui-même n'est pas à blâmer. Notez que l'étiquette a une portée de fonction en C ++, donc elle ne pollue pas la portée globale comme dans un assemblage pur, dans lequel les boucles qui se chevauchent ont leur place et sont très courantes - comme dans le code suivant pour 8051, où l'affichage à 7 segments est connecté à P1. Le programme boucle le segment de la foudre autour de:
Il y a un autre avantage: goto peut servir de boucles nommées, de conditions et d'autres flux:
Ou vous pouvez utiliser un goto équivalent avec indentation, vous n'avez donc pas besoin de commentaire si vous choisissez judicieusement le nom de l'étiquette:
la source
En Perl, utilisation d'une étiquette pour "goto" à partir d'une boucle - en utilisant une "dernière" instruction, qui est similaire à break.
Cela permet un meilleur contrôle sur les boucles imbriquées.
L' étiquette goto traditionnelle est également prise en charge, mais je ne suis pas sûr qu'il existe trop d'exemples où c'est la seule façon d'atteindre ce que vous voulez - les sous-programmes et les boucles devraient suffire dans la plupart des cas.
la source
goto &subroutine
. Ce qui démarre le sous-programme avec le @_ courant, tout en remplaçant le sous-programme actuel dans la pile.Le problème avec «goto» et l'argument le plus important du mouvement de «programmation sans goto» est que si vous l'utilisez trop fréquemment, votre code, bien qu'il puisse se comporter correctement, devient illisible, non maintenable, non révisable, etc. Dans 99,99% des le cas «goto» mène au code spaghetti. Personnellement, je ne vois aucune bonne raison pour laquelle j'utiliserais «goto».
la source
goto
). L'utilisation de @ cschol est similaire: bien qu'il ne conçoive peut-être pas de langage en ce moment, il évalue essentiellement les efforts du concepteur.goto
sauf dans des contextes où il entraînerait l'existence de variables est susceptible d'être moins cher que d'essayer de prendre en charge tous les types de structure de contrôle dont quelqu'un pourrait avoir besoin. Écrire du code avecgoto
peut ne pas être aussi agréable que d'utiliser une autre structure, mais pouvoir écrire un tel code avecgoto
aidera à éviter les "trous dans l'expressivité" - des constructions pour lesquelles un langage est incapable d'écrire du code efficace.goto
sur le site de révision du code, l'élimination de lagoto
simplifie considérablement la logique du code.Le GOTO peut être utilisé, bien sûr, mais il y a une chose plus importante que le style de code, ou si le code est ou non lisible que vous devez avoir à l'esprit lorsque vous l'utilisez: le code à l'intérieur peut ne pas être aussi robuste que vous pense .
Par exemple, regardez les deux extraits de code suivants:
Un code équivalent avec GOTO
La première chose que nous pensons est que le résultat des deux bits de code sera cette "valeur de A: 0" (nous supposons une exécution sans parallélisme, bien sûr)
Ce n'est pas correct: dans le premier échantillon, A sera toujours égal à 0, mais dans le deuxième échantillon (avec l'instruction GOTO), A pourrait ne pas être égal à 0. Pourquoi?
La raison en est qu'à partir d'un autre point du programme, je peux insérer un
GOTO FINAL
sans contrôler la valeur de A.Cet exemple est très évident, mais à mesure que les programmes se compliquent, la difficulté de voir ce genre de choses augmente.
Des documents connexes peuvent être trouvés dans le célèbre article de M. Dijkstra "Un cas contre la déclaration GO TO"
la source
J'utilise goto dans le cas suivant: lorsque nécessaire pour revenir de fonctions à différents endroits, et avant le retour, une désinitialisation doit être effectuée:
version non goto:
version goto:
La deuxième version le rend plus facile, lorsque vous devez changer quelque chose dans les instructions de désallocation (chacune est utilisée une fois dans le code), et réduit les chances d'ignorer l'une d'entre elles, lors de l'ajout d'une nouvelle branche. Les déplacer dans une fonction n'aidera pas ici, car la désallocation peut se faire à différents "niveaux".
la source
finally
blocs en C #finally
). Comme alternative, utilisezgoto
s, mais point de sortie commun , qui fait toujours tout le nettoyage. Mais chaque méthode de nettoyage peut soit gérer une valeur nulle ou déjà propre, soit être protégée par un test conditionnel, donc sautée lorsqu'elle n'est pas appropriée.goto
s qui vont tous même point de sortie, qui a la même logique (ce qui nécessite un supplément si par ressource, comme vous le dites). Mais peu importe, lorsqueC
vous avez raison, quelle que soit la raison pour laquelle le code est en C, c'est presque certainement un compromis qui favorise le code le plus "direct". (Ma suggestion traite des situations complexes où une ressource donnée peut ou non avoir été allouée. Mais oui, exagéré dans ce cas.)Edsger Dijkstra, un informaticien qui a apporté une contribution majeure sur le terrain, était également célèbre pour avoir critiqué l'utilisation de GoTo. Il y a un court article sur son argument sur Wikipedia .
la source
Il est pratique pour le traitement de chaîne de caractères de temps en temps.
Imaginez quelque chose comme cet exemple printf-esque:
Vous pouvez refactoriser cela
goto handle_literal
en un appel de fonction, mais s'il modifie plusieurs variables locales différentes, vous devrez transmettre des références à chacune à moins que votre langage ne prenne en charge les fermetures mutables. Vous devez toujours utiliser uncontinue
instruction (qui est sans doute une forme de goto) après l'appel pour obtenir la même sémantique si votre logique fait que le cas else ne fonctionne pas.J'ai également utilisé judicieusement des gotos dans des lexers, généralement pour des cas similaires. Vous n'en avez pas besoin la plupart du temps, mais ils sont agréables à avoir pour ces cas étranges.
la source