Aktuelle Zeit: 15.11.2018 13:15

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste
Autor Nachricht
 Betreff des Beitrags: Warum Goto und Gosub nur mit Vorsicht gebrauchen.
BeitragVerfasst: 16.10.2005 18:27 
Offline
Benutzeravatar

Registriert: 21.04.2005 22:08
Wohnort: Braunschweig
Warum man Goto und Gosub nicht benutzen soll, Sie aber trotzdem manchmal gebraucht werden.

Damals in den Anfangstagen der Basicprogrammierung war die Sprache Basic sehr Zeilenorientiert.
Man hat vor jeder Zeile eine Zeilenummer mitprogrammiert.
Diese Zeilennummer war dann wie eine Sprungmarke. Damit konnte man nun im Programm sagen das das Programm z.B. von Zeile 10 in die Zeile 30 Springen soll und da weitermachen soll.

Code:
10 if Zahl = 1 then goto 30
20 print "Zahl ist nicht 1 !!"
30 print "Zahl ist 1!!"


Man hat die Zeilen in 10er Schritten Nummeriert um Später Zeilen einfügen zu können.

Code:
10 if Zahl = 1 then goto 30
11 if Zahl = 2 then goto 31
20 print "Zahl ist nicht 1 und nicht 2!!"
30 print "Zahl ist 1!!"
31 print "Zahl ist 2!!"


Auch PureBasic bietet so etwas wie Sprungmarken an.
Eine Sprungmarke ist einfach ein Wort mit einem Doppelpunkt am ende.
z.B. SpringeHierHin:

Code:
If OpenConsole()
  lZahl = 5

  Select lZahl
    Case 1
      Goto Melde1
    Case 2
      Goto Melde2
    Case 3
      Goto Melde3
    Case 4
      Goto Melde4
    Case 5
      Goto Melde5
    Case 6
      Goto Melde6
    Default
      Goto MeldeNix
  EndSelect

  Melde1:
  PrintN("Die Zahl ist 1!")

  Melde2:
  PrintN("Die Zahl ist 2!")

  Melde3:
  PrintN("Die Zahl ist 3!")

  Melde4:
  PrintN("Die Zahl ist 4!")

  Melde5:
  PrintN("Die Zahl ist 5!")
  Goto ProgrammEnde

  Melde6:
  PrintN("Die Zahl ist 6!")

  MeldeNix:
  PrintN("Die Zahl wurde nicht gefunden!")

  ProgrammEnde:
  PrintN("....druecke Enter.....")
  Input()
  CloseConsole()
  End
EndIf


Wenn man jetzt nun die Zeile lZahl = 5 in lZahl = 4 oder lZahl = 1 ändert und das Programm ausführt, wird einem schnell klar, das man auf den Programmverlauf nach der Sprungmarke sehr gut aufpassen muss.
Wenn man einen sehr langen Quelltext hat, wird es für den Programmierer sehr sehr schwer, das hin und her gehüpfe, kreuz und quer durch den Quelltext zu verfolgen.
Das nennt man in der Fachsprache "Spagetticode" weil es nur sehr schwer zu verfolgen ist.

Schnell passieren Fehler, die in einer Endlosschleife oder gar zum Programmabsturz führen.

Code:
If OpenConsole()
Anfang:
  lZahl = 1

  Select lZahl
    Case 1
      Goto Melde1
    Case 2
      Goto Melde2
    Case 3
      Goto Melde3
    Case 4
      Goto Melde4
    Case 5
      Goto Melde5
    Case 6
      Goto Melde6
    Default
      Goto MeldeNix
  EndSelect

  Melde1:
  PrintN("Die Zahl ist 1!")

  Melde2:
  PrintN("Die Zahl ist 2!")

  Melde3:
  PrintN("Die Zahl ist 3!")

  Melde4:
  PrintN("Die Zahl ist 4!")

  Melde5:
  PrintN("Die Zahl ist 5!")
  Goto ProgrammEnde

  Melde6:
  PrintN("Die Zahl ist 6!")

  MeldeNix:
  PrintN("Die Zahl wurde nicht gefunden!")

  ProgrammEnde:
  PrintN("....druecke Enter.....")
  Input()
  Goto Anfang
  CloseConsole()
  End
EndIf


Bei Modernen Programmiersprachen, wie auch PureBasic, nutzt man Prozeduren oder Funktionen als Sprungmarken.
Diese Prozeduren oder Funktionen werden angesprungen, der dort enthaltene Code wird ausgeführt und das Programm geht automatisch an den Ort zurück von wo die Prozedur aufgerufen wurde.
Die Programmsteuerung ist also von vorne herein geregelt und leicht nachvollziehbar.

Code:
Global lZahl1,lZahl2,lErgebnis

Procedure Rechne()
  lErgebnis = lZahl1 + lZahl2
EndProcedure

If OpenConsole()

  lZahl1 = 5
  lZahl2 = 6

  Rechne()

  PrintN("Ergebnis = " + Str(lErgebnis))
  PrintN("....druecke Enter.....")
  Input()
EndIf
End


Deshalb sollte man die Proceduren nutzen, die auch noch mehrer andere vorteile haben in Bezug der Gültigkeit der Variablen und mehr.

Es gibt jedoch einen Vorteil den das Gespann aus Goto und Sprungmarke hat.
Eine Sprungmarke ist beim Programmablauf eine Speicheradresse in die das Programm sehr leicht springen kann ohne vorher zu suchen.
Das Gespann aus Goto und Sprungmarke ist also schneller als ein Sprung zu einer Prozedur und wieder zurück.
Bei sehr Zeitkritischen schnellen Operationen kann man Goto und Sprungmarke nutzen.

Wenn aber aus irgendwelchen Gründen die Sprungmarke (Speicheradresse) falsch oder Ungültig ist dann springt das Goto ins ungewisse!!!!!!!!!!



Gosub, Return und FakeReturn

Gosub ist eine Abkürzung für 'Go to sub routine', es ist also auch ein Goto das weiterentwickelt wurde. Nach Gosub muss auch eine Sprungmarke angegeben werden.
Ist im Programm ein Gosub, so merkt sich das Progamm im Stack die Speicheradresse, von der Stelle wo das Gosub steht (die Adresse wird auf den Stack gelegt, Stack = Spezieller Speicher der sich Sachen merkt).
Nun kann man später an diese stelle wieder zurückkehren, weil man sich die Adresse gemerkt hat.

Dann wird die Programmausführung ab der Sprungmarke weitergeführt, bis ein Return auftaucht. Return heißt soviel wie: Kehre zu der stelle zurück an der das Gosub stand (die stellen haben wir uns im Stack gemerkt).
Nach Return kann der Stack die gemerkte Adresse wieder „vergessen“.

Wenn also das Return erreicht wurde, wird die Programmausführung hinter dem aufrufenden Gosub fortgesetzt.
Genauso Funktionieren auch Proceduren! Proceduren sind aus mehreren gründen vorzuziehen!

Gosub ist aber nützlich, um einigermaßen strukturierten Code zu erstellen der in der Ausführung schnell ist.

Code:
 
a = 1
  b = 2
  Gosub ComplexOperation
  PrintNumberN(a)
  End

  ComplexOperation:
    a = b*2+a*3+(a+b)
    a = a+a*a
  Return



Wenn Sie aus der Gosub-Routine mit dem Befehl Goto in einen anderen Programmteil außerhalb der Gosub-Routine springen möchten , müssen Sie FakeReturn benutzen, um ein Return zu simulieren, ohne es wirklich auszuführen (englisch Fake = gefälscht). Wenn Sie diesen Befehl nicht benutzen, wird Ihr Programm abstürzen. Diese Funktion sollte nutzlos sein, da ein ordentlich aufgebautes und strukturiertes Programm kein Goto benutzt.

Code:
 
Gosub SubRoutine1

  SubRoutine1:
    ...
    If a = 10
      FakeReturn
      Goto Main_Loop
    EndIf
  Return


In einem Programm das nur mit Goto und Gosub Programmiert ist sind alle Variablen Global und somit unsicher vor versehentlichen Veränderungen!

Weil Goto und Gosub so viele Nachteile haben, hat man die Funktionen und Proceduren entwickelt.
Die Prozeduren sind also eine Weiterentwicklung.
Wer sich Programmiertechnisch weiter entwickeln will, nutzt Prozeduren.



Proceduren haben gegenüber Goto und Gosub folgende Vorteile:

* Der Programmablauf ist Leichter nachvollziehbar
* die Variablen in Prozeduren und Programm haben ordentlich definierte Gültigkeitsbereiche
* Prozeduren haben definierte Übergabe- und Rückgabeschnittstellen (so wie DLL Libraries)
* Ein Fehlsprung im Speicher ist mit Prozeduren durch die Überprüfung beim Kompelieren nicht Möglich

Goto und Gosub sind schneller….

_________________
Wir Schreiben ein PureBasic Buch.
Auch du kannst mitmachen!
http://www.purearea.net/pb/english/pure ... :Main_Page


Zuletzt geändert von PAMKKKKK am 17.10.2005 16:19, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 16.10.2005 20:38 
Offline
Benutzeravatar

Registriert: 01.10.2005 13:15
Schön erklärt!

Vorher habe ich auch mal in Basic und QBasic programmiert, da gabs noch keine Funktionen / Prozeduren.
Nur in JavaScript, als ich mit dieser Sprache anfing, musste ich mich an Funktionen bzw. Prozeduren gewöhnen, aber das war gar nicht schwer!
Man sollte meiner Meinung nach aber noch etwas erwähnen.
Code:
Goto starte_hier

unter_programm1:
  text$ = "Beschriftung des Knopfes"
Return

starte_hier:

OpenWindow(0, 0, 0, 200, 150, #PB_Window_SystemMenu|#PB_Window_ScreenCentered, "Fenstertitel")
CreateGadgetList(WindowID(0))
  ;
  ;
  ; gaaaaanz viele Gadgets (Knöpfe, Eingabefelder, usw.)
  ;
  Gosub unter_programm1
  ButtonGadget(1, 10, 10, 100, 25, text$)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
End
Das Ganze ist nicht so kompliziert, wie es aussieht. Als erstes springt das Programm zur Marke (auch "Label" genannt) namens starte_hier. Dann erstellt es ein Fenster mit vielen Gadgets. Zum Schluss kommt noch ein Knopf, dessen Aufschrift in der Variablen text$ gespeichert ist. Diese Variable steht aber weiter oben im Programm. Also springt es eben schnell zum unter_programm1. Dort wird die Variable text$ mit dem String "Beschriftung des Knopfes" gefüllt. Dann gehts mit dem Return wieder zurück da, wo das Programm den kleinen Ausflug gestartet hat. Nun erstellt es den Knopf mit der Aufschrift, die in text$ gespeichert ist.

Hier nochmal das Gleiche, aber mit Prozeduren:
Code:

Procedure. s unter_programm1()
  ProcedureReturn "Aufschrift des Knopfes"
EndProcedure

OpenWindow(0, 0, 0, 200, 150, #PB_Window_SystemMenu|#PB_Window_ScreenCentered, "Fenstertitel")
CreateGadgetList(WindowID(0))
  ;
  ;
  ; gaaaaanz viele Gadgets (Knöpfe, Eingabefelder, usw.)
  ;
text$ = unter_programm1()
  ButtonGadget(1, 10, 10, 100, 25, text$)

Hier entfallen nicht nur die Befehle Gosub und Return, sondern auch die Labels. Ebenso wird nicht in der Prozedur unter_programm1() die Variable text$ mit "Aufchrift des Knopfes" gefüllt, sondern das geschieht 1 Zeile vor dem Knopf, da die Prozedur den String zurückgibt.

Beide Beispiele haben aber einen Nachteil, der noch erwähnt werden sollte. Und zwar wird das Programm an der Stelle vor dem Knopf so lange angehalten, bis die Variable ext$ gefüllt ist.

Man kann Prozeduren auch so aufrufen, dass sie ihre Arbeit erledigen, ohne, dass das Programm so lange angehalten wird. Nämlich mit
Code:
CreateThread(@unter_programm1(), 0)

Diesen Vorteil hat man zusätzlich noch bei Prozeduren.

_________________
PB 4.30
Code:
Macro Happy
 ;-)
EndMacro

Happy End


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 16.10.2005 20:54 
Offline
Benutzeravatar

Registriert: 21.04.2005 22:08
Wohnort: Braunschweig
@AND51
Weder beim Goto, Gosub noch bei Proceduren wird etwas angehalten!
Das Programm läuft einfach einen anderen Weg weiter.
Ader hälst du beim Fahren an, nur weil du in eine andere Strasse abbiegst?? :wink: :wink: :wink: :wink:

_________________
Wir Schreiben ein PureBasic Buch.
Auch du kannst mitmachen!
http://www.purearea.net/pb/english/pure ... :Main_Page


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 16.10.2005 21:34 
Offline
Benutzeravatar

Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg
Und es ist mir neu ... das QBasic keine Prozeduren kann ... im Editor heißen die nur SUB ... und Funktionen gibt es dort auch ... das einzige was anders ist, dass diese im Editor in einem eigenen Fenster angezeigt werden.

MFG PMV

_________________
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 17.10.2005 07:49 
Offline
Benutzeravatar

Registriert: 21.04.2005 22:08
Wohnort: Braunschweig
@AND51
Danke für deinen Vergleichsbeispiel Gosub und Proceduren.
Werde es im Wiki mit einbauen.

PureBasic Dokumentieren, mach mit! :allright:
http://www.purearea.net/pb/english/purewiki/index.php/De:Main_Page

_________________
Wir Schreiben ein PureBasic Buch.
Auch du kannst mitmachen!
http://www.purearea.net/pb/english/pure ... :Main_Page


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 17.10.2005 14:21 
Offline
Benutzeravatar

Registriert: 01.10.2005 13:15
Weder beim Goto, Gosub noch bei Proceduren wird etwas angehalten!
Das Programm läuft einfach einen anderen Weg weiter.

Das stimmt. In dem Sinne wird nichts angehalten, ich habe mich falsch ausgedrückt.
Was ich meinte ist folgendes:
Ich habe gerade ein Programm, das erstellt ein Fenster mit Gadgets und soll gleichzeitig die verfügbaren IPs auf dem Computer ermitteln.
Wenn ich das mit den ersten beiden Beispielen realisieren würde, würde der letzte Knopf solange nicht erstellt, bis die IPs ermittelt wurden (die bei mir im unter_programm1 ermittelt werden).
Das meinte ich in diesem Sinne mit "Das Programm wird angehalten".

Möchte ich aber beide Vorgänge parallel (gleichzeitig) ablaufen lassen, könnte ich noch vor OpenWindow() die Prozedur unter_programm1 (wo ja die IPs ermittelt werden) mittels CreateThread() aufrufen.
Das bewirkt, dass die auf dem Computer verfügbaren IPs ermittelt werden, während ich das fenster mit den Gadgets erstellen lasse.
Das ist oben genau dasselbe: Noch während die Gadgets + fenster erstellt werden, wird schon die Variable text$ mit "beschriftung des Knopfes" abgefüllt.

Wenn man diese Technik nicht nur mit so kleinen popeligen Sachen wie hier anwendet, sondern mit umfangreicheren Code und außerdem öfter auf CreateThread() zurückgreift, kann man den Programmablauf beschleunigen. Das geht mit einfachem Aufrufen einer Prozedur oder unter Verwendung von Gosub+Return/Goto nicht.

Und es ist mir neu ... das QBasic keine Prozeduren kann ... im Editor heißen die nur SUB
Sorry, das stimmt. Es gibt diese besagten SUBs. QBasic kennt SUBs, nur soweit war ich in QB (QBasic) noch nicht. Ich glaube, in der gleichen Zeit, in der ich mit QB programmiert habe (und (ich schätze) 25% von QB gelernt habe), werde ich in PB schon mehr ((ich schätze wieder) 42%) kennen und können.

Danke für deinen Vergleichsbeispiel Gosub und Proceduren.
Bitte, bitte. Den habe ich von Anfängern für Anfänger geschrieben (bin ja selber noch "fortgeschrittener" Anfänger).

Werde es im Wiki mit einbauen.
Cool! Insgeheim, wenn ich ehrlich bin, habe ich das irgendwie gehofft <) . Wird man da auch irgendwie namentlich erwähnt? Meine Signatur AND reicht schon...

_________________
PB 4.30
Code:
Macro Happy
 ;-)
EndMacro

Happy End


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 22.12.2005 19:41 
Offline
verheiratet<br>1. PureGolf-Gewinner
Benutzeravatar

Registriert: 29.08.2004 09:42
Wohnort: Old Europe
Da schau her...dieser Thread ist schon Steinalt und ich lese ihn jetzt
erst.

Pamkkkk,...ich will hier nicht wieder in das Thema "Goto/Gosub sinnvoll ?"
einsteigen, aber solche Aussagen wie von dir z.B.

Zitat:
...das hin und her gehüpfe, kreuz und quer durch den Quelltext zu verfolgen.
Das nennt man in der Fachsprache "Spagetticode" weil es nur sehr schwer zu verfolgen ist.

sind weit hergeholt. Wer gegen Goto´s ist, wird immer solche extrem-Beispiele
bringen.

Ich sage: Wer mit Goto's nicht umgehen kann, kann auch ansonsten
nicht "strukturiert" programmieren. Ein klares Goto an geeigneten Stellen
ist mir 100x lieber als eine x-fach verschachtelte Strukturscheisse.

_________________
Basic Pur = PureBasic


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 22.12.2005 19:53 
Offline
Benutzeravatar

Registriert: 08.09.2004 00:57
Wohnort: Berlin
Solange das goto innerhalb des Hauptprogrammes, bzw. innerhalb einer Prozedure bleibt, ist es manchmal wirklich effizienter. Sollte aber innerhalb eines Programmes eher die Ausnahme als die Regel sein.

_________________
PureBasic 5.70 | SpiderBasic 2.10 | Windows 10 Pro (x64) | Linux Mint 19.0 (x64)
"Ich möchte gerne die Welt verändern, doch Gott gibt den Quellcode nicht frei."
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 22.12.2005 21:08 
Offline
XMas-Contest-Gewinner '03
Benutzeravatar

Registriert: 29.08.2004 14:35
Wohnort: Ingelheim
Und was ist gegen Gosub...Return einzuwenden???

Das ist ein Stück Code das man irgendwo hinpackt (Sinnvollerweise ans Ende des Quellcodes,
vorher ein End zur Sicherheit), und der Aufruf ist wie bei einer Prezedur auch...
Fazit: Gosub ist dein Freund!

_________________
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 22.12.2005 21:22 
Offline
Benutzeravatar

Registriert: 08.09.2004 00:57
Wohnort: Berlin
Gosub : Return wird ja als Unterprogramm benutzt, hierfür ist eine Prozedure besser, wegen lokaler Variablen usw.
Bei der Spieleprogrammierung mag Gosub ja noch manchmal sinnvoll sein, da es etwas schneller als Proceduren ist, aber bei GUI-Anwendungen sollte man wohl eher auf Gosub verzichten.

_________________
PureBasic 5.70 | SpiderBasic 2.10 | Windows 10 Pro (x64) | Linux Mint 19.0 (x64)
"Ich möchte gerne die Welt verändern, doch Gott gibt den Quellcode nicht frei."
Bild


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye