Jeder kennt Dijkstras Briefe an den Herausgeber: Gehen Sie zu einer Aussage, die als schädlich angesehen wird (auch hier .html-Transkript und hier .pdf), und seitdem gab es einen gewaltigen Druck, die goto-Aussage nach Möglichkeit zu vermeiden. Mit goto können Sie zwar nicht wartbaren, weitläufigen Code erzeugen, dieser bleibt jedoch in modernen Programmiersprachen erhalten . Sogar die erweiterte Struktur zur Fortsetzung der Steuerung in Schema kann als hochentwickeltes Goto beschrieben werden.
Welche Umstände rechtfertigen die Verwendung von goto? Wann ist es am besten zu vermeiden?
Als Folgefrage: C bietet ein Paar von Funktionen, setjmp und longjmp, die die Möglichkeit bieten, nicht nur innerhalb des aktuellen Stapelrahmens, sondern innerhalb eines der aufrufenden Rahmen zu gelangen. Sollten diese als so gefährlich wie goto angesehen werden? Gefährlicher?
Dijkstra selbst bedauerte diesen Titel, für den er nicht verantwortlich war. Am Ende von EWD1308 (auch hier .pdf) schrieb er:
Zum Schluss noch eine Kurzgeschichte. 1968 veröffentlichten die Mitteilungen der ACM einen meiner Texte unter dem Titel " Die goto-Erklärung als schädlich ", auf den in späteren Jahren am häufigsten Bezug genommen wurde, leider jedoch häufig von Autoren, die nicht mehr davon gesehen hatten als seine Titel, der zu einem Eckpfeiler meines Ruhms wurde, indem er zu einer Vorlage wurde: Wir würden alle Arten von Artikeln unter dem Titel "X als schädlich angesehen" für fast jedes X sehen, einschließlich eines mit dem Titel "Dijkstra als schädlich". Aber was war passiert? Ich hatte ein Papier unter dem Titel " Ein Fall gegen die goto-Erklärung " eingereicht", der, um seine Veröffentlichung zu beschleunigen, in einen" Brief an den Herausgeber "umgewandelt worden war und ihm dabei einen neuen Titel seiner eigenen Erfindung gegeben hatte! Der Herausgeber war Niklaus Wirth.
Ein gut durchdachtes klassisches Papier zu diesem Thema, das mit dem von Dijkstra übereinstimmt, ist Structured Programming with go to Statements von Donald E. Knuth. Das Lesen hilft sowohl, den Kontext wiederherzustellen, als auch ein nicht dogmatisches Verständnis des Themas. In diesem Artikel wird die Meinung von Dijkstra zu diesem Fall berichtet und ist noch stärker:
Donald E. Knuth: Ich glaube, dass ich durch die Darstellung einer solchen Ansicht den Ideen von Dijkstra nicht scharf widerspreche, da er kürzlich Folgendes geschrieben hat: "Bitte geraten Sie nicht in die Falle, zu glauben, dass ich schrecklich dogmatisch gegenüber [dem gehe zu Aussage]. Ich habe das unangenehme Gefühl, dass andere eine Religion daraus machen, als ob die konzeptuellen Probleme der Programmierung durch einen einzigen Trick, durch eine einfache Form der Codierungsdisziplin gelöst werden könnten! "
quelle
goto
.goto
: Hacken strukturierter Programmierwerkzeuge zusammen, um a zu implementierengoto
.Antworten:
Die folgenden Aussagen sind Verallgemeinerungen; Während es immer möglich ist, eine Ausnahme zu plädieren, ist es normalerweise (meiner Erfahrung und bescheidenen Meinung nach) das Risiko nicht wert.
Fußnoten zu den oben genannten:
Beachten Sie in Bezug auf Punkt 2 den folgenden Code:
An der Stelle "etwas tun" im Code können wir mit hoher Sicherheit angeben, dass
a
größer als istb
. (Ja, ich ignoriere die Möglichkeit eines nicht eingefangenen Ganzzahlüberlaufs. Lassen Sie uns kein einfaches Beispiel festhalten.)Auf der anderen Seite, wenn der Code so gelesen hätte:
Die Vielzahl der Möglichkeiten, um zu Label 10 zu gelangen, bedeutet, dass wir viel härter arbeiten müssen, um uns über die Beziehungen zwischen
a
undb
zu diesem Zeitpunkt sicher zu sein . (In der Tat ist es im allgemeinen Fall unentscheidbar!)In Bezug auf Punkt 4 ist der gesamte Begriff "irgendwohin gehen" im Code nur eine Metapher. Nichts "geht" wirklich irgendwo in der CPU außer Elektronen und Photonen (für die Abwärme). Manchmal geben wir eine Metapher für eine andere, nützlichere auf. Ich erinnere mich, dass ich (vor einigen Jahrzehnten!) Einer Sprache begegnet bin, in der
wurde auf einer virtuellen Maschine implementiert, indem Aktion 1 und Aktion 2 als parametrlose Routinen außerhalb der Zeile kompiliert wurden und dann ein einzelner VM-Opcode mit zwei Argumenten verwendet wurde, der den booleschen Wert der Bedingung zum Aufrufen der einen oder anderen verwendete. Das Konzept war einfach "wählen, was jetzt aufgerufen werden soll" anstatt "hierher oder dorthin gehen". Wieder nur eine Änderung der Metapher.
quelle
true
undfalse
sind von unterschiedlicher Art), und jeder Zweig eines if / else ist im Grunde ein Lambda.goto
in einer modernen Programmiersprache (Go) stackoverflow.com/a/11065563/3309046 .Ein Mitarbeiter von mir sagte, der einzige Grund, ein GOTO zu verwenden, sei, wenn Sie sich so weit in eine Ecke programmiert haben, dass dies der einzige Ausweg ist. Mit anderen Worten, richtiges Design im Voraus und Sie müssen später kein GOTO mehr verwenden.
Ich dachte, dieser Comic zeigt auf wundervolle Weise: "Ich könnte den Programmfluss umstrukturieren oder stattdessen ein kleines 'GOTO' verwenden." Ein GOTO ist ein schwacher Ausweg, wenn Sie ein schwaches Design haben. Velociraptors jagen den Schwachen nach .
quelle
Manchmal ist es gültig, GOTO als Alternative zur Ausnahmebehandlung innerhalb einer einzelnen Funktion zu verwenden:
COM-Code scheint ziemlich oft in dieses Muster zu fallen.
quelle
Ich kann mich nur daran erinnern, ein goto einmal benutzt zu haben. Ich hatte eine Reihe von fünf verschachtelten gezählten Schleifen und musste unter bestimmten Bedingungen frühzeitig von innen aus der gesamten Struktur ausbrechen können:
Ich hätte einfach eine boolesche Unterbrechungsvariable deklarieren und als Teil der Bedingung für jede Schleife verwenden können, aber in diesem Fall entschied ich, dass ein GOTO genauso praktisch und genauso lesbar ist.
Keine Velociraptoren haben mich angegriffen.
quelle
goto
uns auflehnte und uns strukturierte Programme gab, lehnte aus demselben Grund auch frühe Renditen ab. Es kommt darauf an, wie lesbar der Code ist, wie deutlich er die Absicht des Programmierers ausdrückt. Das Erstellen einer Funktion für keinen anderen Zweck als die Vermeidung der Verwendung eines bösartigen Schlüsselworts führt zu einem schlechten Zusammenhalt: Die Heilung ist schlechter als die Krankheit.goto
kann man das Ziel explizit angeben. Mitbreak 5;
(1) muss ich Schleifenschließungen zählen, um das Ziel zu finden; und (2) wenn sich die Schleifenstruktur jemals ändert, kann es durchaus erforderlich sein, diese Nummer zu ändern, um das Ziel korrekt zu halten. Wenn ich es vermeiden will,goto
sollte der Gewinn darin liegen, dass ich solche Dinge nicht manuell verfolgen muss.Wir hatten diese Diskussion bereits und ich stehe zu meinem Standpunkt .
Darüber hinaus bin ich mit Menschen zu beschreiben geordnete Sprachstrukturen als „satt
goto
in der Verkleidung“ , weil sie eindeutig nicht den Punkt bekam überhaupt . Zum Beispiel:Das ist völliger Unsinn. Jede Kontrollstruktur kann in Bezug auf implementiert werden,
goto
aber diese Beobachtung ist völlig trivial und nutzlos.goto
wird wegen seiner positiven Auswirkungen nicht als schädlich angesehen, sondern wegen seiner negativen Folgen, die durch strukturierte Programmierung beseitigt wurden.In ähnlicher Weise ist die Aussage „GOTO ist ein Werkzeug, und wie alle Werkzeuge kann es verwendet und missbraucht werden“ völlig falsch. Kein moderner Bauarbeiter würde einen Stein benutzen und behaupten, er sei „ein Werkzeug“. Steine wurden durch Hämmer ersetzt.
goto
wurde durch Kontrollstrukturen ersetzt. Wenn der Bauarbeiter ohne Hammer in freier Wildbahn gestrandet wäre, würde er natürlich stattdessen einen Stein verwenden. Wenn eine Programmiererin eine minderwertige Programmiersprache verwenden muss, die nicht über Feature X verfügt, muss sie möglicherweisegoto
stattdessen eine Programmiersprache verwenden . Aber wenn sie es irgendwo anders anstelle der entsprechenden Sprachfunktion verwendet, hat sie die Sprache offensichtlich nicht richtig verstanden und verwendet sie falsch. So einfach ist das wirklich.quelle
goto
. Sie haben insofern Recht, als ichgoto
per se kein Argument dagegen vorbringe - ich hatte nicht vor -, also gibt es keine Fragen.Goto steht auf meiner Liste der Dinge, die nur deswegen in ein Programm aufgenommen werden sollen, ganz unten. Das heißt nicht, dass es inakzeptabel ist.
Gehe zu kann für Zustandsautomaten schön sein. Eine switch-Anweisung in einer Schleife ist (in der Reihenfolge ihrer typischen Bedeutung): (a) nicht repräsentativ für den Kontrollfluss, (b) hässlich, (c) je nach Sprache und Compiler möglicherweise ineffizient. Am Ende schreiben Sie eine Funktion pro Status und führen Dinge wie "return NEXT_STATE;" die sehen sogar aus wie goto.
Zugegeben, es ist schwierig, Zustandsautomaten so zu codieren, dass sie leicht verständlich sind. Keine dieser Schwierigkeiten hat jedoch mit der Verwendung von goto zu tun, und keine davon kann durch die Verwendung alternativer Kontrollstrukturen verringert werden. Es sei denn, Ihre Sprache verfügt über ein Konstrukt "Zustandsmaschine". Meins nicht.
In den seltenen Fällen, in denen Ihr Algorithmus in Bezug auf einen Pfad durch eine Folge von Knoten (Zuständen), die durch eine begrenzte Anzahl zulässiger Übergänge (gotos) verbunden sind, am verständlichsten ist, und nicht durch einen spezifischeren Kontrollfluss (Schleifen, Bedingungen usw.) ), dann sollte das im Code explizit sein. Und Sie sollten ein hübsches Diagramm zeichnen.
setjmp / longjmp kann nützlich sein, um Ausnahmen oder ausnahmeähnliches Verhalten zu implementieren. Obwohl nicht allgemein gelobt, werden Ausnahmen im Allgemeinen als "gültige" Kontrollstruktur angesehen.
setjmp / longjmp sind "gefährlicher" als goto in dem Sinne, dass sie schwerer richtig zu verwenden sind, egal verständlich.
Das Entfernen von goto aus C würde es nicht einfacher machen, guten Code in C zu schreiben. Tatsächlich würde es eher den Punkt verfehlen, dass C in der Lage sein soll , als verherrlichte Assembler-Sprache zu fungieren.
Als nächstes wird es "Zeiger als schädlich" sein, dann "Ententypisierung als schädlich". Wer bleibt dann übrig, um Sie zu verteidigen, wenn er Ihr unsicheres Programmierkonstrukt wegnimmt? Eh?
quelle
Unter Linux: Verwenden von goto In Kernel Code auf Kernel Trap gibt es eine Diskussion mit Linus Torvalds und einem "neuen Mann" über die Verwendung von GOTOs in Linux-Code. Es gibt einige sehr gute Punkte und Linus hat diese übliche Arroganz angezogen :)
Einige Passagen:
- -
- -
quelle
goto cleanup_and_exit
ist eine der wenigen „gut“ Verwendungen gehe links jetzt, wo wir habenfor
,while
undif
unser Steuerfluss zu verwalten. Siehe auch: programmers.stackexchange.com/a/154980Funktioniert in C
goto
nur im Rahmen der aktuellen Funktion, wodurch potenzielle Fehler lokalisiert werden.setjmp
undlongjmp
sind weitaus gefährlicher, nicht lokal, kompliziert und implementierungsabhängig. In der Praxis sind sie jedoch zu dunkel und ungewöhnlich, um viele Probleme zu verursachen.Ich glaube, dass die Gefahr von
goto
in C stark übertrieben ist. Denken Sie daran, dass die ursprünglichengoto
Argumente in den Tagen von Sprachen wie altmodischem BASIC stattfanden, in denen Anfänger Spaghetti-Code wie folgt schrieben:Hier beschreibt Linus eine geeignete Verwendung von
goto
: http://www.kernel.org/doc/Documentation/CodingStyle (Kapitel 7).quelle
setjmp
/longjmp
nur angegeben wurde, wenn sie als Mittel zum Springen zu einem Punkt innerhalb eines Bereichs von anderen Orten innerhalb desselben Bereichs verwendet wurden. Sobald das Steuerelement den Bereich verlässt, in demsetjmp
es ausgeführt wird, führt jeder Versuch, dielongjmp
von erstellte Struktur zu verwenden, zu einemsetjmp
undefinierten Verhalten.GOTO A * 40 + B * 200 + 30
. Es ist nicht schwer zu sehen, wie praktisch und sehr gefährlich dies war.Heutzutage ist die große Sache mit der
GOTO
Aussage schwer zu erkennen, da die Leute mit "strukturierter Programmierung" die Debatte meistens gewonnen haben und die heutigen Sprachen über ausreichende Kontrollflussstrukturen verfügen, um dies zu vermeidenGOTO
.Zählen Sie die Anzahl der
goto
s in einem modernen C-Programm. Fügen Sie nun die Anzahl derbreak
,continue
undreturn
Aussagen. Darüber hinaus fügen Sie die Anzahl der Male , die Sie verwendenif
,else
,while
,switch
odercase
. Das ist ungefähr, wie vieleGOTO
s Ihr Programm gehabt hätte, wenn Sie 1968 in FORTRAN oder BASIC geschrieben hätten, als Dijkstra seinen Brief schrieb.Zu dieser Zeit fehlten die Programmiersprachen im Kontrollfluss. Zum Beispiel im Original Dartmouth BASIC:
IF
Aussagen hatten keineELSE
. Wenn Sie einen wollten, mussten Sie schreiben:Auch wenn Ihre
IF
Aussage keine benötigteELSE
, war sie dennoch auf eine einzelne Zeile beschränkt, die normalerweise aus einer bestandGOTO
.Es gab keine
DO...LOOP
Aussage. Für Nicht-FOR
Schleifen mussten Sie die Schleife mit einem explizitenGOTO
oderIF...GOTO
zurück zum Anfang beenden .Es gab keine
SELECT CASE
. Du musstest benutzenON...GOTO
.So endete Sie mit einer bis Menge von
GOTO
s in Ihrem Programm. Und Sie konnten sich nicht auf die Beschränkung vonGOTO
s auf eine einzelne Subroutine verlassen (weil diesGOSUB...RETURN
ein so schwaches Konzept von Subroutinen war), so dass dieseGOTO
s überall hingehen konnten . Dies machte es offensichtlich schwierig, dem Kontrollfluss zu folgen.Hierher kam die Anti-
GOTO
Bewegung.quelle
420 if (rare_condition) then 3000
//430 and onward: rest of loop and other main-line code
//3000 [code for rare condition]
// wäre3230 goto 430
. Das Schreiben von Code auf diese Weise vermeidet genommene Verzweigungen oder Sprünge im allgemeinen Hauptzeilenfall, macht es jedoch schwierig, den Dingen zu folgen. Die Vermeidung von Verzweigungen im Assembler-Code kann schlechter sein, wenn einige Verzweigungen auf z. B. +/- 128 Byte beschränkt sind und manchmal keine komplementären Paare haben (z. B. "cjne" existiert, aber nicht "cje").cjne r0,expected_value,first_comp_springboard
/.../cjne r1,unexpected_value,second_comp_fallthrough
// `ajmp second_comp_target` //first_comp_springboard: ajmp first_comp_target
//second_comp_fallthrough: ...
. Kein sehr schönes Codierungsmuster, aber wenn einzelne Zyklen zählen, macht man solche Dinge. In den 1960er Jahren waren solche Optimierungsstufen natürlich wichtiger als heute, zumal moderne CPUs häufig seltsame Optimierungen erfordern und Just-in-Time-Kompilierungssysteme möglicherweise Optimierungscode für CPUs anwenden können, die zu diesem Zeitpunkt nicht vorhanden waren Der betreffende Code wurde geschrieben.Go To kann in bestimmten Fällen eine Art Ersatz für die "echte" Ausnahmebehandlung bieten. Erwägen:
Offensichtlich wurde dieser Code vereinfacht, um weniger Platz zu beanspruchen. Lassen Sie sich also nicht zu sehr auf die Details ein. Aber denken Sie an eine Alternative, die ich allzu oft im Produktionscode von Codierern gesehen habe, die absurde Längen gegangen sind, um die Verwendung von goto zu vermeiden:
Funktionell macht dieser Code genau das Gleiche. Tatsächlich ist der vom Compiler generierte Code nahezu identisch. In dem Eifer des Programmierers, Nogoto (den gefürchteten Gott der akademischen Zurechtweisung) zu beschwichtigen , hat dieser Programmierer jedoch die zugrunde liegende Redewendung, die die
while
Schleife darstellt, vollständig gebrochen und eine echte Zahl für die Lesbarkeit des Codes angegeben. Das ist nicht besser.Die Moral der Geschichte lautet also: Wenn Sie auf etwas wirklich Dummes zurückgreifen, um die Verwendung von goto zu vermeiden, dann tun Sie es nicht.
quelle
break
Anweisungen innerhalb einer Kontrollstruktur befinden, genau klar, was sie tun. In diesemgoto
Beispiel muss die Person, die den Code liest, den Code durchsehen, um die Bezeichnung zu finden, die theoretisch tatsächlich vor der Kontrollstruktur liegen könnte. Ich habe nicht genug Erfahrung mit altmodischem C, um zu beurteilen, dass eines definitiv besser ist als das andere, aber es gibt Kompromisse in beiden Richtungen.break
s in einer Schleife befinden, macht genau klar, dass sie die Schleife verlassen . Das ist nicht "genau das, was sie tun", da es in Wirklichkeit überhaupt keine Schleife gibt! Nichts darin hat jemals die Chance, sich zu wiederholen, aber das ist bis zum Ende nicht klar. Die Tatsache, dass Sie eine "Schleife" haben, die nie mehr als einmal ausgeführt wird, bedeutet, dass Kontrollstrukturen missbraucht werden. Mit demgoto
Beispiel kann der Programmierer sagengoto error_handler;
. Es ist expliziter und noch weniger schwer zu befolgen. (Strg + F, "error_handler:", um das Ziel zu finden. Versuchen Sie dies mit "}".)Donald E. Knuth beantwortete diese Frage im Buch "Literate Programming", 1992 CSLI. Auf P. 17 gibt es einen Aufsatz " Strukturierte Programmierung mit goto-Anweisungen " (PDF). Ich denke, der Artikel könnte auch in anderen Büchern veröffentlicht worden sein.
Der Artikel beschreibt den Vorschlag von Dijkstra und beschreibt die Umstände, unter denen dies gültig ist. Er gibt aber auch eine Reihe von Gegenbeispielen (Probleme und Algorithmen) an, die nicht einfach nur mit strukturierten Schleifen reproduziert werden können.
Der Artikel enthält eine vollständige Beschreibung des Problems, den Verlauf, Beispiele und Gegenbeispiele.
quelle
Goto als hilfreich angesehen.
Ich habe 1975 mit dem Programmieren begonnen. Für Programmierer aus den 1970er Jahren sagten die Worte "gehe als schädlich" mehr oder weniger, dass neue Programmiersprachen mit modernen Kontrollstrukturen einen Versuch wert waren. Wir haben die neuen Sprachen ausprobiert. Wir haben schnell konvertiert. Wir sind nie zurückgegangen.
Wir sind nie zurückgegangen, aber wenn Sie jünger sind, waren Sie noch nie dort.
Ein Hintergrund in alten Programmiersprachen ist möglicherweise nur als Indikator für das Alter des Programmierers sehr nützlich. Ungeachtet dessen fehlt jüngeren Programmierern dieser Hintergrund, so dass sie die Botschaft, die der Slogan "Goto als schädlich" an das beabsichtigte Publikum zum Zeitpunkt seiner Einführung übermittelte , nicht mehr verstehen .
Slogans, die man nicht versteht, sind nicht sehr aufschlussreich. Es ist wahrscheinlich am besten, solche Slogans zu vergessen. Solche Slogans helfen nicht.
Dieser spezielle Slogan "Goto gilt als schädlich" hat jedoch ein Eigenleben für Untote aufgenommen.
Kann man nicht missbraucht werden? Antwort: sicher, aber was nun? Praktisch jedes Programmierelement kann missbraucht werden. Die Demütigen
bool
zum Beispiel werden häufiger missbraucht, als einige von uns glauben möchten.Im Gegensatz dazu kann ich mich nicht erinnern, seit 1990 einen einzigen tatsächlichen Fall von Missbrauch erlebt zu haben.
Das größte Problem mit goto ist wahrscheinlich nicht technisch, sondern sozial. Programmierer, die nicht viel wissen, scheinen manchmal das Gefühl zu haben, dass sie durch die Ablehnung von goto klug klingen. Möglicherweise müssen Sie solche Programmierer von Zeit zu Zeit zufriedenstellen. So ist das Leben.
Das Schlimmste an goto heute ist, dass es nicht genug verwendet wird.
quelle
Von Jay Ballou angezogen, der eine Antwort hinzufügt, füge ich meine £ 0,02 hinzu. Wenn Bruno Ranschaert dies nicht bereits getan hätte, hätte ich Knuths Artikel "Strukturierte Programmierung mit GOTO-Anweisungen" erwähnt.
Eine Sache, die ich nicht besprochen habe, ist die Art von Code, der, obwohl nicht gerade üblich, in Fortran-Lehrbüchern gelehrt wurde. Dinge wie der erweiterte Bereich einer DO-Schleife und offen codierter Unterprogramme (denken Sie daran, dies wäre Fortran II oder Fortran IV oder Fortran 66 - nicht Fortran 77 oder 90). Es besteht zumindest die Möglichkeit, dass die syntaktischen Details ungenau sind, aber die Konzepte sollten genau genug sein. Die Snippets befinden sich jeweils in einer einzigen Funktion.
Beachten Sie, dass das ausgezeichnete, aber veraltete (und vergriffene) Buch ' The Elements of Programming Style, 2. Aufl. ' Von Kernighan & Plauger einige Beispiele aus der Praxis des Missbrauchs von GOTO aus Programmierlehrbüchern seiner Zeit (Ende der 70er Jahre) enthält. Das folgende Material stammt jedoch nicht aus diesem Buch.
Erweiterter Bereich für eine DO-Schleife
Ein Grund für diesen Unsinn war die gute altmodische Lochkarte. Möglicherweise stellen Sie fest, dass sich die Beschriftungen (nicht in der richtigen Reihenfolge, da dies ein kanonischer Stil war!) In Spalte 1 befinden (tatsächlich mussten sie sich in den Spalten 1 bis 5 befinden) und der Code in den Spalten 7 bis 72 (Spalte 6 war die Fortsetzung) Markierungsspalte). Die Spalten 73-80 erhielten eine Sequenznummer, und es gab Maschinen, die Lochkartenstapel in der Reihenfolge der Sequenznummern sortierten. Wenn Sie Ihr Programm auf sequenzierten Karten hatten und ein paar Karten (Zeilen) in die Mitte einer Schleife einfügen müssten, müssten Sie nach diesen zusätzlichen Zeilen alles neu starten. Wenn Sie jedoch eine Karte durch das GOTO-Material ersetzt haben, können Sie vermeiden, dass alle Karten neu geordnet werden. Sie haben die neuen Karten am Ende der Routine nur mit neuen Sequenznummern versehen. Betrachten Sie es als den ersten Versuch von "Green Computing"
Oh, Sie könnten auch bemerken, dass ich betrüge und nicht schreie - Fortran IV wurde normalerweise in Großbuchstaben geschrieben.
Open-Coded-Subroutine
Das GOTO zwischen den Labels 76 und 54 ist eine Version des berechneten goto. Wenn die Variable i den Wert 1 hat, gehe zum ersten Label in der Liste (123); Wenn es den Wert 2 hat, gehe zum zweiten und so weiter. Das Fragment von 76 bis zum berechneten goto ist die offen codierte Subroutine. Es war ein Code, der wie eine Unterroutine ausgeführt, aber im Hauptteil einer Funktion geschrieben wurde. (Fortran hatte auch Anweisungsfunktionen - eingebettete Funktionen, die in eine einzelne Zeile passten.)
Es gab schlechtere Konstrukte als das berechnete goto - Sie konnten Variablen Beschriftungen zuweisen und dann ein zugewiesenes goto verwenden. Googeln zugewiesen goto sagt mir, dass es aus Fortran 95 gelöscht wurde. Kreide eins für die strukturierte Programmierrevolution, die mit Dijkstras "GOTO Considered Harmful" Brief oder Artikel öffentlich begonnen haben könnte.
Ohne ein gewisses Wissen über die Art der Dinge, die in Fortran (und in anderen Sprachen, von denen die meisten zu Recht auf der Strecke geblieben sind) getan wurden, ist es für uns Neulinge schwierig, den Umfang des Problems zu verstehen, mit dem sich Dijkstra befasste. Heck, ich habe erst zehn Jahre nach Veröffentlichung dieses Briefes mit dem Programmieren begonnen (aber ich hatte das Unglück, eine Weile in Fortran IV zu programmieren).
quelle
goto
"in the wild" verwendet, zeigt die Frage " Gesucht: Funktionierender Bose-Hibbard-Sortieralgorithmus" einen 1963 veröffentlichten (Algol 60) Code. Das ursprüngliche Layout ist nicht mit modernen Codierungsstandards vergleichbar. Der geklärte (eingerückte) Code ist immer noch ziemlich unergründlich. Diegoto
Aussagen dort tun es (sehr) schwer zu verstehen , was der Algorithmus ist oben.Es gibt keine Dinge, die GOTO als schädlich erachtet .
GOTO ist ein Werkzeug, und wie alle Werkzeuge kann es verwendet und missbraucht werden .
Es gibt jedoch viele Tools in der Programmierwelt, die dazu neigen, mehr missbraucht als verwendet zu werden , und GOTO ist eines davon. Die WITH- Anweisung von Delphi ist eine andere.
Persönlich verwende ich auch keinen typischen Code , aber ich hatte die seltsame Verwendung von GOTO und WITH , die gerechtfertigt war, und eine alternative Lösung hätte mehr Code enthalten.
Die beste Lösung wäre, wenn der Compiler Sie nur warnt, dass das Schlüsselwort fehlerhaft ist , und Sie müssten ein paar Pragma-Anweisungen um die Anweisung setzen, um die Warnungen zu entfernen.
Es ist, als würde man seinen Kindern sagen, sie sollen nicht mit einer Schere rennen . Scheren sind nicht schlecht, aber ihre Verwendung ist möglicherweise nicht der beste Weg, um Ihre Gesundheit zu erhalten.
quelle
goto
Schlüsselwort aus C # entfernt wurde, existiert das Konzept "hier springen" in IL immer noch. Eine Endlosschleife kann leicht ohne das Schlüsselwort goto erstellt werden. Wenn dieser Mangel an Garantie, dass der aufgerufene Code zurückgegeben wird, Ihrer Meinung nach bedeutet, dass "nicht in der Lage ist, über den Code nachzudenken", dann würde ich sagen, dass wir diese Fähigkeit nie hatten.goto
in C # ist kein echtes "goto" im ursprünglichen Sinne des Wortes. Es ist eine viel schwächere Version, die nur das Springen innerhalb einer Funktion erlaubt. Der Sinn, in dem ich "goto" verwende, ermöglicht es, überall im Prozess zu springen. Obwohl C # ein "goto" -Schlüsselwort hat, hatte es wohl noch nie ein echtes goto. Ja, auf IL-Ebene ist ein echtes Goto verfügbar, genauso wie wenn eine Sprache bis zur Assemblierung kompiliert wird. Der Programmierer ist jedoch davor geschützt und kann ihn unter normalen Umständen nicht verwenden. Daher zählt er nicht.Es war nie so lange, wie Sie selbst denken konnten.
quelle
Seit ich ein paar Dinge im Linux-Kernel gemacht habe, stören mich gotos nicht mehr so sehr wie früher. Zuerst war ich irgendwie entsetzt zu sehen, dass sie (Kernel-Leute) meinem Code Gotos hinzugefügt haben. Seitdem habe ich mich in einigen begrenzten Zusammenhängen an die Verwendung von gotos gewöhnt und werde sie jetzt gelegentlich selbst verwenden. In der Regel ist es ein Goto, der zum Ende einer Funktion springt, um eine Art Bereinigung und Rettung durchzuführen, anstatt dieselbe Bereinigung und Rettung an mehreren Stellen in der Funktion zu duplizieren. Und normalerweise ist es nicht groß genug, um an eine andere Funktion übergeben zu werden - z. B. ist das Freigeben einiger lokal (k) mallocierter Variablen ein typischer Fall.
Ich habe Code geschrieben, der setjmp / longjmp nur einmal verwendet hat. Es war in einem MIDI-Drum-Sequenzer-Programm. Die Wiedergabe erfolgte in einem von allen Benutzerinteraktionen getrennten Prozess, und der Wiedergabevorgang verwendete gemeinsam genutzten Speicher mit dem UI-Prozess, um die begrenzten Informationen zu erhalten, die für die Wiedergabe erforderlich waren. Wenn der Benutzer die Wiedergabe stoppen wollte, führte der Wiedergabevorgang nur einen Longjmp "Zurück zum Anfang" durch, um von vorne zu beginnen, anstatt ein kompliziertes Abwickeln dessen, wo es gerade ausgeführt wurde, als der Benutzer wollte, dass es gestoppt wurde. Es hat großartig funktioniert, war einfach und ich hatte in diesem Fall nie Probleme oder Fehler damit.
setjmp / longjmp haben ihren Platz - aber diesen Ort werden Sie wahrscheinlich nur ab und zu besuchen.
Edit: Ich habe mir gerade den Code angesehen. Es war tatsächlich siglongjmp (), das ich verwendet habe, nicht longjmp (nicht, dass es eine große Sache ist, aber ich hatte vergessen, dass siglongjmp überhaupt existiert.)
quelle
Wenn Sie eine VM in C schreiben, stellt sich heraus, dass Sie (gccs) berechnete gotos wie folgt verwenden:
arbeitet viel schneller als der herkömmliche Schalter innerhalb einer Schleife.
quelle
&&op_inc
sicherlich nicht kompiliert, weil (links)&
einen l-Wert erwartet, aber (rechts)&
einen r-Wert ergibt.Weil
goto
kann für verwirrende Metaprogrammierung verwendet werdenGoto
ist sowohl ein Steuerausdruck auf hoher als auch auf niedriger Ebene und hat daher einfach kein geeignetes Entwurfsmuster, das für die meisten Probleme geeignet ist.Es ist niedrig in dem Sinne, dass ein goto eine primitive Operation ist, die etwas Höheres wie
while
oderforeach
oder etwas implementiert .Es ist auf hoher Ebene in dem Sinne, dass es, wenn es auf bestimmte Weise verwendet wird, Code benötigt, der in einer klaren Reihenfolge und ohne Unterbrechung ausgeführt wird, mit Ausnahme von strukturierten Schleifen, und es in logische Teile umwandelt, die mit genügend
goto
s ein Greifer sind - Beutel mit Logik, die dynamisch wieder zusammengesetzt wird.Es gibt also eine prosaische und eine böse Seite
goto
.Die prosaische Seite ist, dass ein nach oben zeigender Goto eine vollkommen vernünftige Schleife implementieren kann und ein nach unten gerichteter Goto eine vollkommen vernünftige Schleife ausführen kann
break
oderreturn
. Natürlich ein tatsächlichenwhile
,break
oderreturn
wäre viel besser lesbar sein, da der arme Mensch würde nicht die Wirkung, das hat zu simulieren ,goto
um das große Bild zu bekommen. Also eine schlechte Idee im Allgemeinen.Die böse Seite beinhaltet eine Routine, die goto nicht für eine Weile, Pause oder Rückkehr verwendet, sondern für die sogenannte Spaghetti-Logik . In diesem Fall konstruiert der goto-happy-Entwickler Codeteile aus einem Labyrinth von goto's, und der einzige Weg, dies zu verstehen, besteht darin, es mental als Ganzes zu simulieren, eine schrecklich anstrengende Aufgabe, wenn es viele goto's gibt. Ich meine, stellen Sie sich die Mühe vor, Code zu bewerten, bei dem
else
das nicht genau umgekehrt istif
, wo verschachtelteif
s in einigen Dingen, die vom Äußeren abgelehnt wurdenif
, usw. usw. zulassen könnten .Um das Thema wirklich abzudecken, sollten wir schließlich beachten, dass im Wesentlichen alle frühen Sprachen außer Algol zunächst nur einzelne Aussagen gemacht haben, die ihren Versionen von unterliegen
if-then-else
. Die einzige Möglichkeit, einen bedingten Block auszuführen, bestand darin,goto
ihn mit einer inversen Bedingung zu umgehen. Wahnsinnig, ich weiß, aber ich habe einige alte Spezifikationen gelesen. Denken Sie daran, dass die ersten Computer in binärem Maschinencode programmiert wurden. Ich nehme an, dass jede Art von HLL ein Lebensretter war. Ich denke, sie waren nicht zu wählerisch in Bezug auf die HLL-Funktionen, die sie haben.Nachdem ich alles gesagt hatte, was ich
goto
in jedes Programm gesteckt hatte, schrieb ich "nur um die Puristen zu ärgern" .quelle
Den Programmierern die Verwendung der GOTO-Anweisung zu verweigern, ist wie einem Schreiner zu sagen, er solle keinen Hammer verwenden, da dies die Wand beschädigen könnte, während er in einen Nagel hämmert. Ein echter Programmierer weiß, wie und wann ein GOTO zu verwenden ist. Ich bin einigen dieser sogenannten "strukturierten Programme" gefolgt. Ich sehe solch schrecklichen Code, nur um die Verwendung eines GOTO zu vermeiden, dass ich den Programmierer erschießen könnte. Ok, zur Verteidigung der anderen Seite habe ich auch echten Spaghetti-Code gesehen und wieder sollten diese Programmierer auch erschossen werden.
Hier ist nur ein kleines Beispiel für Code, den ich gefunden habe.
-----------------------ODER----------------------
quelle
goto
- und weiß warum . Das Vermeiden eines Tabu-Sprachkonstrukts, weil $ programming_guru dies sagte, ist genau die Definition der Frachtkult-Programmierung."In diesem Link http://kerneltrap.org/node/553/2131 "
Ironischerweise führte das Eliminieren des Goto zu einem Fehler: Der Spinlock-Aufruf wurde weggelassen.
quelle
Das Originalpapier sollte als "Unbedingte GOTO als schädlich angesehen" betrachtet werden. Es befürwortete insbesondere eine Form der Programmierung, die auf bedingten (
if
) und iterativen (while
) Konstrukten basiert , und nicht auf dem für frühen Code üblichen Test-and-Jump.goto
ist in einigen Sprachen oder Umständen immer noch nützlich, in denen keine geeignete Kontrollstruktur vorhanden ist.quelle
Ich bin damit einverstanden, dass Goto nur verwendet werden kann, wenn Sie sich mit Fehlern befassen müssen und jeder einzelne Punkt, an dem ein Fehler auftritt, eine spezielle Behandlung erfordert.
Wenn Sie beispielsweise Ressourcen abrufen und Semaphoren oder Mutexe verwenden, müssen Sie diese in der richtigen Reihenfolge abrufen und sollten sie immer auf die entgegengesetzte Weise freigeben.
Einige Codes erfordern ein sehr seltsames Muster beim Abrufen dieser Ressourcen, und Sie können nicht einfach eine leicht zu wartende und verständliche Kontrollstruktur schreiben, um sowohl das Abrufen als auch das Freigeben dieser Ressourcen korrekt zu handhaben und einen Deadlock zu vermeiden.
Es ist immer möglich, es richtig zu machen, ohne zu gehen, aber in diesem und einigen anderen Fällen ist Goto tatsächlich die bessere Lösung, vor allem für Lesbarkeit und Wartbarkeit.
-Adam
quelle
Eine moderne GOTO-Verwendung besteht darin, dass der C # -Compiler Zustandsmaschinen für Enumeratoren erstellt, die durch Yield Return definiert sind.
GOTO sollte von Compilern und nicht von Programmierern verwendet werden.
quelle
goto
. Wo wirgoto
in einer von Hand codierten Zustandsmaschine einen Enumerator implementieren könnten , können wiryield
stattdessen einfach verwenden .Bis C und C ++ (unter anderem Schuldige) Pausen markiert haben und fortfahren, wird goto weiterhin eine Rolle spielen.
quelle
Wenn GOTO selbst böse wäre, wären Compiler böse, weil sie JMPs generieren. Wenn das Springen in einen Codeblock, insbesondere nach einem Zeiger, von Natur aus böse wäre, wäre die RETurn-Anweisung böse. Vielmehr besteht das Böse im Missbrauchspotential.
Manchmal musste ich Apps schreiben, die eine Reihe von Objekten verfolgen mussten, bei denen jedes Objekt als Reaktion auf Ereignisse einer komplizierten Folge von Zuständen folgen musste, aber das Ganze war definitiv ein einzelner Thread. Eine typische Folge von Zuständen, wenn sie im Pseudocode dargestellt werden, wäre:
Ich bin sicher, dass dies nicht neu ist, aber ich habe es in C (++) so gehandhabt, dass ich einige Makros definiert habe:
Dann (unter der Annahme, dass der Zustand anfänglich 0 ist) verwandelt sich die obige strukturierte Zustandsmaschine in den strukturierten Code:
Mit einer Variation davon kann es CALL und RETURN geben, so dass einige Zustandsautomaten sich wie Unterprogramme anderer Zustandsautomaten verhalten können.
Ist es ungewöhnlich Ja. Benötigt der Betreuer etwas Lernen? Ja. Lohnt sich dieses Lernen? Ich glaube schon. Könnte es ohne GOTOs gemacht werden, die in Blöcke springen? Nee.
quelle
Ich vermeide es, da ein Mitarbeiter / Manager seine Verwendung zweifellos entweder in einer Codeüberprüfung oder wenn er darüber stolpert, in Frage stellen wird. Obwohl ich denke, dass es Verwendungszwecke hat (zum Beispiel den Fall der Fehlerbehandlung), werden Sie einem anderen Entwickler zuwiderlaufen, der ein Problem damit hat.
Es lohnt sich nicht.
quelle
Ich sah mich tatsächlich gezwungen, ein goto zu verwenden, weil ich mir buchstäblich keinen besseren (schnelleren) Weg vorstellen konnte, diesen Code zu schreiben:
Ich hatte ein komplexes Objekt und musste es operieren. Wenn sich das Objekt in einem Zustand befand, konnte ich eine schnelle Version der Operation ausführen, andernfalls musste ich eine langsame Version der Operation ausführen. Die Sache war, dass es in einigen Fällen mitten im langsamen Betrieb möglich war zu erkennen, dass dies mit dem schnellen Betrieb hätte geschehen können.
Dies war ein geschwindigkeitskritischer Teil des Echtzeit-UI-Codes, daher denke ich ehrlich, dass ein GOTO hier gerechtfertigt war.
Hugo
quelle
In fast allen Situationen, in denen ein goto verwendet werden kann, können Sie dasselbe mit anderen Konstrukten tun. Springen wird sowieso vom Compiler verwendet.
Ich persönlich benutze es nie explizit, brauche es nie.
quelle
Eine Sache, die ich aus keiner der Antworten hier gesehen habe, ist, dass eine "goto" -Lösung oft effizienter ist als eine der oft erwähnten strukturierten Programmierlösungen.
Betrachten Sie den Fall mit vielen verschachtelten Schleifen, in dem die Verwendung von 'goto' anstelle einer Reihe von
if(breakVariable)
Abschnitten offensichtlich effizienter ist. Die Lösung "Setzen Sie Ihre Schleifen in eine Funktion und verwenden Sie return" ist oft völlig unvernünftig. In dem wahrscheinlichen Fall, dass die Schleifen lokale Variablen verwenden, müssen Sie sie jetzt alle über Funktionsparameter übergeben, um möglicherweise eine Menge zusätzlicher Kopfschmerzen zu bewältigen, die sich daraus ergeben.Betrachten Sie nun den Bereinigungsfall, den ich selbst ziemlich oft verwendet habe und der so häufig vorkommt, dass er vermutlich für die Struktur try {} catch {} verantwortlich war, die in vielen Sprachen nicht verfügbar ist. Die Anzahl der Überprüfungen und zusätzlichen Variablen, die erforderlich sind, um dasselbe zu erreichen, ist weitaus schlechter als die ein oder zwei Anweisungen, um den Sprung auszuführen, und auch hier ist die Lösung für zusätzliche Funktionen überhaupt keine Lösung. Sie können mir nicht sagen, dass dies überschaubarer oder lesbarer ist.
Jetzt sind Code-Speicherplatz, Stack-Nutzung und Ausführungszeit für viele Programmierer in vielen Situationen möglicherweise nicht wichtig genug. Wenn Sie sich jedoch in einer eingebetteten Umgebung mit nur 2 KB Code-Speicherplatz befinden, müssen Sie 50 Byte zusätzliche Anweisungen verwenden, um eine klar definierte zu vermeiden 'goto' ist einfach lächerlich, und dies ist keine so seltene Situation, wie viele hochrangige Programmierer glauben.
Die Aussage, dass "goto is schädlich" ist, war sehr hilfreich bei der Umstellung auf strukturierte Programmierung, auch wenn es sich immer um eine Überverallgemeinerung handelte. Zu diesem Zeitpunkt haben wir alle genug davon gehört, um vorsichtig zu sein (wie wir sollten). Wenn es offensichtlich das richtige Werkzeug für den Job ist, müssen wir uns nicht davor fürchten.
quelle
Sie können es verwenden, um aus einer tief verschachtelten Schleife auszubrechen, aber meistens kann Ihr Code ohne tief verschachtelte Schleifen sauberer gestaltet werden.
quelle