Bedingte Verzweigung - "GoTo" Kluge ? - Seite 4

 

Java läuft auch nicht außerhalb seiner virtuellen Maschine, dort werden Sie die gleichen Probleme haben, Sie können keine DLL erstellen, die von einem C-Programm geladen und aufgerufen werden kann.

Wenn Sie C# mögen, dann werden Sie auch ObjectPascal mögen (die Typsicherheit, die Strenge, die gesamte Philosophie dahinter, mit Ausnahme der VM-Sache). Schließlich ist der Designer und Chefarchitekt von C# die gleiche Person, die einst Turbo-Pascal und Delphi (ObjectPascal) entwickelt hat, und das merkt man. In mancher Hinsicht ist C# wie ObjectPascal mit der (hässlichen, aber heutzutage angesagten) C-Syntax.

Um direkt mit der Maschine und mit C-APIs (wie sie für MetaTrader benötigt werden) zu interagieren und trotzdem eine so mächtige Sprache wie C# zu verwenden, gibt es nicht viele Alternativen zu ObjectPascal. Manche sagen, C++ sei genauso mächtig (und kann natürlich auch anstelle von OP verwendet werden), aber es ist eindeutig nicht so elegant, hat viele Ungereimtheiten und ist so fehleranfällig, dass nur echte Experten es wirklich beherrschen können.

 
7bit:

.... kehrt die Funktion an den Ort zurück, von dem aus sie aufgerufen wurde.

Dies ist der entscheidende Unterschied 7bit: Ich spreche davon, eine völlig andere Funktion, Unterroutine oder sogar importierten Code, ganze Unterroutinen und/oder Funktionen AUßERHALB der aktuellen Funktion aufzurufen. Ein konzeptionelles Beispiel:

Ich befinde mich in einer Funktion, die von Zeile 100 bis Zeile 20 läuft, aber ich möchte etwas aufrufen, das außerhalb dieses Bereichs liegt. Vielleicht eine ganz andere Funktion, die sich in den Zeilen 50 bis 60 befindet. <=-Das passt nicht zu den Parametern und dem obigen Beispiel , nach dem ich frage Es ist ein 100%iger Ersatz für das alte gosub/return und zusätzlich erlaubt die Funktion die Übergabe von Werten und die Rückgabe von Werten.

Sie KÖNNEN mehrere Return-Anweisungen innerhalb derselben Funktion haben und Sie können auch Schleifen mit break .... verlassen .

Verstanden

Aber ich bekomme immer wieder gesagt, dass ich mich innerhalb des Bereichs einer bestimmten Funktion bewegen kann, was ich auch verstehe. Aber das ist NICHT das, wonach ich überhaupt frage , und das habe ich am Anfang von all dem gesagt.

Was also die "Ausnahmen" betrifft, so können Sie sie so nennen, wenn Sie wollen. Wie ich schon sagte, versuche ich, eine Lösung zu finden, um die Funktionalität von Funktionen wie: GoTo, GoSub (außerhalb der CURRENT-Funktion) usw., die nicht direkt als Funktion in MQL4 existieren. Ihren Antworten nach zu urteilen, kennen und verstehen die meisten von Ihnen diese Programmierunterschiede, gehen aber nicht auf die eigentliche Frage ein.

 

FourX:

Ich befinde mich in einer Funktion, die von Zeile 100 bis Zeile 20 läuft, aber ich möchte etwas aufrufen, das außerhalb dieses Bereichs liegt. Vielleicht eine ganz andere Funktion, die sich in den Zeilen 50 bis 60 befindet.
Erstellen Sie eine separate Funktion, die den Code aus den Zeilen 50 bis 60 enthält, dann können Sie diese Funktion jederzeit von einer anderen Funktion aus aufrufen.
 

bedenken Sie dies:

void foo(){
  int x;
  int y;
  y = 33;
  x = 42;
  .LABELFOO
  print(x);
  return;
}

void bar(){
  int x;
  z = 5;
  GOTO .LABELFOO
}

void main(){ //<-- program starts here
  foo();
  bar();
}

Was wird nun passieren? Beginnen wir mit main(), ich werde alle Schritte während der Ausführung erklären (Kommentare sind grün, Anweisungen sind schwarz):

  • (wir sind bei der ersten Zeile in main())
  • schiebe die Rücksprungadresse auf den Stack (benötigt 4 Bytes), das ist die Adresse, an der es weitergeht, sobald der Aufruf von foo() beendet ist (wir müssen uns das merken, damit wir später wissen, wohin wir zurückkehren müssen)
  • Sprung zur ersten Zeile von foo()
  • schiebe 4 Bytes auf den Stack, um Platz für die lokale Variable x zu schaffen
  • schiebe 4 Bytes auf den Stack, um Platz für die lokale Variable y zu schaffen
  • (unser Stack ist jetzt 12 Bytes hoch)
  • schreibe den Long-Wert 33 in die Bytes 0,1,2,3 (von oben auf dem Stack gezählt)
  • schreibe den Long-Wert 42 in die Bytes 4,5,6,7 (von oben auf dem Stack gezählt)
  • Drucke den Long-Wert, der sich in den Bytes 4,5,6,7 befindet (von oben auf dem Stack gezählt)
  • 4 Bytes vom Stapel holen und vergessen (y geht aus dem Bereich)
  • pop 4 Bytes vom Stack und vergiss sie (x geht aus dem Anwendungsbereich)
  • pop 4 Bytes vom Stack, dies ist jetzt die Adresse, von der wir beim Aufruf von foo() gekommen sind, die Rücksprungadresse, springe zu dieser Adresse
  • (jetzt sind wir wieder in main() in der nächsten Zeile, der mit bar())
  • Schiebe die Rücksprungadresse (4 Bytes) auf den Stack
  • springe zur ersten Zeile von bar()
  • schiebe 4 Bytes (lokale Variable x) auf den Stack
  • (unser Stack ist jetzt 8 Bytes hoch)
  • schreibe den langen Wert 5 in die Bytes 0,1,2,3 (von oben auf dem Stack gezählt)
  • Springe zum Label .LABELFOO
  • (Beobachten Sie jetzt genau, wie alles von hier an schrecklich schief läuft. Wir wissen bereits, was alle folgenden Zeilen tun werden, weil ich es oben erklärt habe, sie tun genau dasselbe wie vorher, sie verhalten sich alle so, als hätten sie die oberen 12 Bytes des Stacks zur Verfügung. Aber der Stack hat diesmal nur 8 Bytes! Die nächste Zeile erwartet eine Variable an der Position 4,5,6,7 vom oberen Ende des Stacks, mal sehen, was passiert, hier kommt die Zeile mit dem print)
  • drucke den langen Wert, der sich in den Bytes 4,5,6,7 befindet (vom oberen Ende des Stacks aus gezählt)
  • (oops? das ist nicht unser x, das ist der Rückgabewert, der Stack ist diesmal nur 8 Bytes hoch, es wird eine total unsinnige Zahl gedruckt)
  • 4 Bytes vom Stack abziehen und vergessen (das wäre "y geht aus dem Bereich", aber es ist nicht y, sondern das x aus der anderen Funktion)
  • pop 4 bytes vom Stack und vergiss sie (das wäre "x goes out of scope", aber es ist nicht x, wir haben gerade die Rücksprungadresse weggeworfen!)
  • (der Stack ist jetzt leer!)
  • 4 Bytes vom Stack abziehen, um die Rücksprungadresse zu erhalten -> Absturz!

Die Funktion foo benötigt einen lokalen Stack-Frame von 8 Bytes plus Rücksprungadresse und die Funktion bar nur 4 Bytes plus Rücksprungadresse. Ihre Rücksprunganweisungen haben dies bereits bei der Kompilierung eingebaut, sie holen unterschiedlich viele Bytes vom Stack, man kann nicht einen Rücksprung verwenden, um die Aufgabe des anderen zu erledigen, jeder funktioniert nur für die Funktion, für die er kompiliert wurde.

Diese alten Sprachen, die GOTO im gesamten Programm hatten, hatten keinen lokalen Variablenbereich und das Einzige, was man richtig machen musste, war, dass die Anzahl von GOSUB und RETURN gleich sein musste, alle ihre Rückgaben gaben nur die Rückgabeadresse aus und sonst nichts, alle Rückgaben verhielten sich genau gleich. Aber jetzt haben wir eine Menge unterschiedlich großer "GOSUB "s (jeder schiebt unterschiedliche Beträge auf den Stack) und auch viele unterschiedliche Rückgaben, die unterschiedliche Beträge vom Stack holen. Und wir haben lokale Variablen auf dem Stack. Das kann einfach nicht funktionieren, egal was für verrückte Dinge man versucht, in den Compiler einzubauen.

Theoretisch könnte man innerhalb der *gleichen* Funktion GOTO verwenden (und einige Sprachen erlauben dies), aber Sie können mir kein einziges Stück Code zeigen, bei dem dies tatsächlich zu einem eleganteren, leichter zu verstehenden und besser zu wartenden Code führen würde als eine ordnungsgemäß strukturierte Programmierung. Das einzige, was es bewirken würde, wäre ein furchtbares Durcheinander. Niemand braucht das, also ist es nicht implementiert.

 

Wir alle wissen bereits, dass MQL4 keine nativen Funktionen wie ein GoTo ODER ein 'GoSub -=> ReturnFromGoSub' hat. Das ist unbestritten. Hier geht es jetzt um wiederholte Erklärungen und Beispiele für die Tatsache, dass MQL4 keine solchen nativen Funktionen hat. Das ist kein Argument. Darum geht es in diesem Thread nicht und darum ging es auch nie. Können wir also bitte aufhören, über etwas zu streiten, was wir bereits wissen und worüber wir uns einig sind?

Wir wissen, dass diese Funktionen in anderen Programmiersprachen gültig sind und sehr nützlich sein können.

Der Sinn dieses Threads ist es, herauszufinden, OB wir sie mit dem, was in MQL4 verfügbar ist, simulieren und nutzen können?

Eine gültige Funktionsvervollständigung des zweiten Falles im ersten Satz von'GoSub -=> ReturnFromGoSub ' wäre zum Beispiel zu: Rückkehr zum Punkt des Programms, an dem GoSub aufgerufen wurde, und Rückgabe der Werte von GoSub an den aufrufenden Punkt im Programm.

 
FourX:

Eine gültige Funktionsvervollständigung des zweiten Falls im ersten Satz von"GoSub -=> ReturnFromGoSub " wäre zum Beispiel zu: Rückkehr zum Punkt des Programms, an dem GoSub aufgerufen wurde, und Rückgabe der Werte von GoSub an den aufrufenden Punkt im Programm.


Ihnen wurde wiederholt gesagt, dass es sich bei dem, was Sie beschreiben, um eine benutzerdefinierte Funktion handelt ... warum können Sie das nicht akzeptieren? Bitte geben Sie ein Beispiel mit Pseudocode, warum eine benutzerdefinierte Funktion!= Gosub + Return
 

FourX:

GoSub -=> ReturnFromGoSub ' wäre zu: Rückkehr zum Punkt des Programms, an dem GoSub aufgerufen wurde, und Rückgabe der Werte von GoSub an den aufrufenden Punkt im Programm.

double subtract_two_numbers(double a, double b){
  Print("will now calculate ", a, " minus ", b);
  return(a - b);                                 // <---- THIS IS YOUR RETURN
}

int start(){                                     // <---- PROGRAM STARTS HERE
  double s;
  double d;

  s = subtract_two_numbers(Ask, Bid);            // <---- THIS IS YOUR GOSUB
  d = subtract_two_numbers(Close[0], Open[0]);   // <---- THIS IS YOUR GOSUB

  Print("the spread is ", s);
  Print("price moved ", d, " since the open");
}                                                // <---- PROGRAM ENDS HERE
Da haben Sie Ihr GOSUB und RETURN, direkt in die mql4-Sprache eingebaut, sogar mit der Übergabe von Argumenten und Rückgabewerten, was in Commodore-BASIC oder einer anderen uralten und verkrüppelten Sprache, mit der Sie sie ständig zu vergleichen versuchen, nicht einmal möglich war. Wo sind Sie in den letzten 30 Jahren gewesen?
 

FourX, wenn du mql4 lernst, während dein Verstand noch in BBC Basic ist, denke defproc und proc und vergiss GoTo und GoSub.

Ich hatte in den frühen 80ern einen BBC Micro ....ahhhh ich erinnere mich noch an die Freude, wenn ich versuchte, Programme von seinem Kassettenlaufwerk zu laden :( wir schrieben Programme in BBC Basic

 
SDC:

FourX, wenn du mql4 lernst, während dein Verstand noch in BBC Basic ist, denke defproc und proc und vergiss GoTo und GoSub.

Ich hatte in den frühen 80ern einen BBC Micro ....ahhhh ich erinnere mich noch an die Freude, wenn ich versuchte, Programme von seinem Kassettenlaufwerk zu laden :( wir schrieben Programme in BBC Basic

LOL . . . Ich hatte einen Acorn Electron ... wenn es heiß war, wollte er nichts von einem Band lesen, das ich geschrieben hatte, wenn es kalt war und umgekehrt ... das waren noch Zeiten ;-)
 
RaptorUK:
LOL . . . Ich hatte einen Acorn Electron ... wenn er heiß war, konnte er nichts vom Band lesen, das ich geschrieben hatte, wenn er kalt war und umgekehrt ... das waren noch Zeiten ;-)

Ja, das waren noch Zeiten :) mit einem gebogenen Schraubenzieher an der kleinen Schraube neben den Bandköpfen drehen und dabei immer wieder auf die Seite schlagen haha