
Von der Grundstufe bis zur Mittelstufe: Variablen (II)
Einführung
Die hier vorgestellten Materialien sind ausschließlich für didaktische Zwecke bestimmt. Die Anwendung sollte unter keinen Umständen zu einem anderen Zweck als zum Erlernen und Beherrschen der vorgestellten Konzepte verwendet werden.
Im vorherigen Artikel „Von der Grundstufe zur Mittelstufe: Variablen (I)“ haben wir begonnen, über Variablen und einige mit ihnen verbundene Aspekte zu sprechen. Wir haben zum Beispiel besprochen, wie man Variablen in Konstanten umwandelt. Wir haben auch begonnen, über die Lebensdauer und Sichtbarkeit von Variablen zu sprechen.
Wir werden dieses Thema hier fortsetzen, wobei wir davon ausgehen, dass der Leser das vorherige Material richtig verstanden hat. Eine Sache, die wir bei der Diskussion über die variable Lebensdauer und Sichtbarkeit feststellen, kann für Anfänger etwas schwierig zu verstehen sein. Der Grund dafür ist, dass wir in vielen Fällen nicht wollen, dass globale Variablen Unannehmlichkeiten verursachen. Wir wollen, dass Variablen nur innerhalb eines einzigen Codeblocks existieren. Aber - und hier wird es kompliziert - wir wollen nicht, dass der Wert der Variablen nach dem Ende des Blocks verschwindet.
Diese Situation ist eine die viele Programmierer verwirren, einschließlich der Anfänger, die Profis werden wollen. Dies liegt daran, dass viele Menschen nicht wissen, dass einige Programmiersprachen über Mechanismen verfügen, die es ermöglichen, dass eine Variable ihren Wert im Speicher beibehält. Diese Komplexität ist wahrscheinlich auf die Tatsache zurückzuführen, dass gängige Skriptsprachen wie Python diese Implementierung nicht verwenden. Aus diesem Grund ist es für einen Programmierer, der mit Python vertraut ist, sehr schwierig, dieses Konzept zu verstehen. Variablen verlieren nicht immer ihren Wert, wenn der Block, zu dem sie gehören, nicht mehr existiert, oder besser gesagt, sie vergessen ihn.
C/C++-Programmierer sind jedoch im Allgemeinen mit diesem Konzept gut vertraut, da es tief in ihrer Erfahrung verwurzelt ist. Da MQL5 diesen Sprachen ähnlich ist, hat es dieses Prinzip übernommen - eine Funktion, die meiner Meinung nach sehr vorteilhaft ist. Ohne sie müssten sich Entwickler auf globale Variablen innerhalb des Anwendungsbereichs verlassen, was oft eine erhebliche Unannehmlichkeit darstellt.
Um zu erklären, wie das funktioniert, beginnen wir mit einem neuen Thema.
Statische Variablen
Statische Variablen sind eines der leistungsfähigsten und gleichzeitig eines der schwierigsten Konzepte für viele Programmieranfänger. Auf den ersten Blick scheinen sie oft kontraintuitiv zu sein. Wenn Sie sie jedoch studieren und zu verstehen beginnen, wie sie funktionieren, insbesondere wann und wo sie angewendet werden können, werden Sie ihren Nutzen vielleicht sehr zu schätzen wissen. Sie lösen viele Probleme, die sonst nur mit sehr viel mehr Aufwand zu lösen wären.
Beginnen wir mit einem recht einfachen Fall. Obwohl wir uns noch nicht mit bestimmten Programmierkonzepten befasst haben, möchte ich Sie bitten, sich vorerst nur auf die Variablen zu konzentrieren. Vergessen Sie alles andere. Versuchen Sie zu verstehen, was mit den Variablen geschieht, denn das ist der entscheidende Punkt, den es hier zu erfassen gilt.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. uchar counter = 0; 07. ulong value = 1; 08. 09. Print("Factorial of ", counter, " => ", value); 10. counter = counter + 1; 11. value = value * counter; 12. Print("Factorial of ", counter, " => ", value); 13. counter = counter + 1; 14. value = value * counter; 15. Print("Factorial of ", counter, " => ", value); 16. counter = counter + 1; 17. value = value * counter; 18. Print("Factorial of ", counter, " => ", value); 19. counter = counter + 1; 20. value = value * counter; 21. Print("Factorial of ", counter, " => ", value); 22. } 23. //+------------------------------------------------------------------+
Code 01
Ich weiß, wir könnten hier eine Schleife verwenden. Nehmen wir jedoch an, dass Sie beim Erlernen des Programmierens ganz von vorne anfangen. Sie wissen absolut nichts über das Thema, und alles, was Sie bisher gelernt haben, basiert auf dem vorherigen Artikel. In diesem Sinne müssen wir ganz von vorne anfangen. Am Anfang mag es sich etwas komplizierter anfühlen, aber es wird bald besser werden.
Das wichtigste Detail dabei ist folgendes: Wenn wir Code 01 im MetaTrader 5-Terminal ausführen, wird das Ergebnis wie unten dargestellt sein.
Abbildung 01
Wie Sie sehen können, funktioniert es. Hier geht es darum, die Fakultät einer Zahl zu berechnen. Aber anstatt es einfach zu berechnen und das Ergebnis zurückzuliefern, zerlegen wir es und berechnen es Schritt für Schritt. Diese Herangehensweise ist für das Verständnis meines Anliegens unerlässlich.
Nun, liebe Leserinnen und Leser, bedenken Sie Folgendes: In Zeile sechs erstellen und initialisieren wir eine Variable. Diese Variable verfolgt die aktuell berechnete Fakultät. Dann deklarieren wir in Zeile sieben eine weitere Variable und initialisieren sie mit einem entsprechenden Wert. Und ja, die Fakultät von Null ist Eins, so wie die Fakultät von Eins auch Eins ist. Dieses Wissen ist für jede Programmieraufgabe von entscheidender Bedeutung, denn beim Programmieren geht es darum, Probleme mathematisch zu lösen. Im Gegensatz zu dem, was viele Menschen glauben, nämlich dass Programmieren einfach nur bedeutet, beliebige Befehle einzugeben und den Computer dazu zu bringen, sie auszuführen, besteht das Wesen des Programmierens darin, mathematische Formeln in einen Code zu verwandeln, den eine Maschine verstehen kann. Aus diesem Grund ist ein solides Verständnis der Mathematik unerlässlich, um ein guter Programmierer zu werden.
Um auf unsere Frage zurückzukommen, geben wir in den Zeilen 09, 12, 15, 18 und 21 die Ergebnisse in einer für Menschen lesbaren Form aus. Zwischen jedem dieser Schritte weisen wir die Maschine an, wie sie den nächsten Wert berechnen soll. Achten Sie jetzt auf diesen kritischen Punkt: Jedes Mal, wenn wir die Fakultät der aktuellen Zahl berechnen, verwenden wir den Wert der vorherigen Fakultät. Mit anderen Worten: Auch wenn die Variablen Zähler und Wert ursprünglich Konstanten sind, ändern sich diese konstanten Werte bei jeder neuen Berechnung und werden zu neuen Konstanten. Dies ist eines der grundlegendsten Konzepte über Variablen, das Sie als Programmierer für den Rest Ihrer Karriere mit sich führen sollten.
Da wir nun auf derselben Seite stehen, können wir versuchen, die Dinge zu vereinfachen, indem wir die Anzahl der Codezeilen reduzieren. Um dies zu erreichen, müssen wir ein anderes Konzept verwenden, das später genauer erklärt wird, aber an dieser Stelle ist es notwendig. Dieses Konzept ist Routine.
Eine Routine ist im Wesentlichen eine Aufgabe, die die Maschine ausführt, wenn wir sie dazu auffordern. Man kann sich das als eine sich wiederholende und mühsame Aufgabe vorstellen, die wir nicht jedes Mal als Code neu schreiben wollen. Dies entspricht dem, was in mehreren Zeilen von Code 01 geschieht. Es gibt im Wesentlichen zwei Arten von Routinen: Funktionen und Methoden. Um statische Variablen zu erklären, werden wir jedoch eine Methode verwenden, da sie eine einfachere Möglichkeit bietet, die Vorgänge zu verstehen.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. uchar counter = 0; 05. ulong value = 1; 06. //+------------------------------------------------------------------+ 07. void OnStart(void) 08. { 09. Factorial(); 10. Factorial(); 11. Factorial(); 12. Factorial(); 13. Factorial(); 14. } 15. //+------------------------------------------------------------------+ 16. void Factorial(void) 17. { 18. Print("Factorial of ", counter, " => ", value); 19. counter = counter + 1; 20. value = value * counter; 21. } 22. //+------------------------------------------------------------------+
Code 02
Beachten Sie, dass der Code 02 viel einfacher zu verstehen ist. Auf den ersten Blick fällt auf, dass wir die faktoriellen Werte von null bis vier berechnen. Dies ist darauf zurückzuführen, dass innerhalb des Hauptcodeblocks, der OnStart-Methode, vier Aufrufe der Factorial-Methode erfolgen. Wie bereits erwähnt, werden wir uns damit später befassen. Aber jetzt wollen wir uns erst einmal auf das Verständnis der Variablen konzentrieren.
Beachten Sie, dass trotz des offensichtlichen Unterschieds zwischen Code 01 und Code 02 das Ergebnis in beiden Fällen Abbildung 01 sein wird. Hier in Code 02 verwenden wir jedoch zwei globale Variablen, die bei der Ausführung des Codes erscheinen und erst wieder verschwinden, wenn der Code beendet ist. Von einem Moment auf den anderen können dieselben Variablen von jeder Methode oder Funktion, die Zugriff auf sie hat, geändert werden. Selbst wenn diese Änderung auf unseren Fehler oder unser Versehen bei der Implementierung des Codes zurückzuführen ist. Dies ist bei komplexen Codes nicht unüblich.
Auch wenn diese Variablen global sind und zu keinem bestimmten Block gehören, müssen diese Werte initialisiert werden. Wie Sie sehen können, führen wir die Initialisierung in dem Moment durch, in dem wir sie deklarieren. Dies kann jedoch auch zu jedem anderen Zeitpunkt geschehen, was es schwierig macht, mögliche Wertänderungen zu verfolgen. Der Einfachheit halber initialisieren wir sie aber gleich bei der Deklaration. An dieser Stelle stellt sich eine durchaus berechtigte Frage: Wenn ich etwas Komplexes entwerfe und befürchte, dass ich während des Programmierens versehentlich die Werte globaler Variablen ändere, wäre es dann nicht besser, die Variablen Zähler und Wert innerhalb der Factorial-Methode zu deklarieren? Auf diese Weise würden wir nicht riskieren, diese Variablen ungewollt zu verändern.
Ja, liebe Leserin, lieber Leser, der beste Ansatz wäre in der Tat, Zähler und Wert aus dem globalen Bereich zu entfernen und sie innerhalb der Factorial-Methode zu deklarieren. Auf diese Weise hätten wir eine bessere Kontrolle über die Variablen im Code. Lassen Sie uns also diese Anpassung vornehmen und sehen, was passiert. Auf den ersten Blick scheinen sowohl Code 01 als auch Code 02 wie vorgesehen zu funktionieren. Und wenn sie funktionieren, bedeutet das, dass wir auf dem richtigen Weg sind. Durch die Umsetzung der vorgeschlagenen Änderung wird der aktualisierte Code wie folgt aussehen:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. Factorial(); 07. Factorial(); 08. Factorial(); 09. Factorial(); 10. Factorial(); 11. } 12. //+------------------------------------------------------------------+ 13. void Factorial(void) 14. { 15. uchar counter = 0; 16. ulong value = 1; 17. 18. Print("Factorial of ", counter, " => ", value); 19. counter = counter + 1; 20. value = value * counter; 21. } 22. //+------------------------------------------------------------------+
Code 03
Großartig! Jetzt haben wir nicht mehr das Problem der globalen Variablen im Code. Unser Programm ist in der Tat viel besser organisiert. Aber was ist mit dem Ergebnis? Berechnen wir immer noch die faktoriellen Werte von null bis vier? Sehen wir es uns an. Nach dem Kompilieren des Codes und der Ausführung im MetaTrader 5-Terminal wird das folgende Ergebnis angezeigt:
Abbildung 02
Warten Sie... Es hat nicht geklappt. Aber warum? Es hat vorher funktioniert. Jetzt bin ich wirklich verwirrt, denn auf den ersten Blick sieht es so aus, als würden wir den Code fünfmal ausführen, wie erwartet. Es sieht jedoch so aus, als würden wir immer auf die gleichen Werte verweisen. Hmm, lassen Sie mich kurz nachdenken. Bleiben Sie dran.
Ah, jetzt habe ich es verstanden! Jedes Mal, wenn einer der Aufrufe im Hauptblock (die OnStart-Methode) ausgeführt wird, werden die Variablen „counter“ und „value“ neu deklariert. Und jedes Mal, wenn wir dies tun, werden sie auch auf die zuvor im Code definierten Anfangswerte zurückgesetzt. Das ist der Grund, warum es nicht funktioniert hat! Dies half mir, das Konzept der Lebensdauer einer Variablen zu verstehen. Aber ich habe noch eine Frage: Was passiert, wenn ich die Werte in den Zeilen 15 und 16 nicht initialisiere? Vielleicht würde das funktionieren! Nein, liebe Leserin, lieber Leser, das könnten Sie versuchen, aber Sie würden auf die Probleme stoßen, die wir im vorigen Artikel besprochen haben.
Könnten wir also stattdessen die Werte an die Methode übergeben? Das würde funktionieren. Ja, in diesem Fall würde es das Problem lösen. Dieser Ansatz wäre jedoch verfrüht. Da ich noch nicht erklärt habe, wie man Werte zwischen Prozeduren und Funktionen übergibt, können Sie diese Technik noch nicht verwenden. Sie müssen einen anderen Weg finden, damit Code 03 funktioniert und die gleiche Ausgabe wie in Abbildung 01 zeigt und nicht dieses seltsame Ergebnis, das wir in Abbildung 02 sehen. Geben Sie auf?
Wenn das der Fall ist, ist es an der Zeit, Ihrer Frustration ein Ende zu bereiten. Um dieses Problem zu lösen, ohne auf irgendwelche „Zaubereien“ zurückzugreifen und gleichzeitig die Variablen Zähler und Wert innerhalb der Factorial-Prozedur zu behalten, müssen wir eine so genannte statische Variable verwenden. Wenn eine Variable als statisch deklariert ist, verliert sie ihren Wert nicht zwischen verschiedenen Aufrufen derselben Prozedur oder Funktion. Klingt das kompliziert? Das mag auf den ersten Blick so aussehen, aber in der Praxis ist es viel einfacher, als es scheint. Solange du darauf achtest, was du tust, wird alles gut gehen. Wenn Sie jedoch unvorsichtig sind, können die Dinge schnell außer Kontrolle geraten. Um dies besser zu verstehen, sehen wir uns einmal an, wie der Code in der Praxis aussehen würde. Sie können die aktualisierte Version unten sehen: Wenn eine Variable als statisch deklariert ist, verliert sie ihren Wert nicht zwischen verschiedenen Aufrufen derselben Prozedur oder Funktion.
Klingt das kompliziert? Das mag auf den ersten Blick so aussehen, aber in der Praxis ist es viel einfacher, als es scheint. Solange du darauf achtest, was du tust, wird alles gut gehen. Wenn Sie jedoch unvorsichtig sind, können die Dinge schnell außer Kontrolle geraten. Um dies besser zu verstehen, sehen wir uns einmal an, wie der Code in der Praxis aussehen würde. Er ist unten zu sehen.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. Factorial(); 07. Factorial(); 08. Factorial(); 09. Factorial(); 10. Factorial(); 11. } 12. //+------------------------------------------------------------------+ 13. void Factorial(void) 14. { 15. static uchar counter = 0; 16. static ulong value = 1; 17. 18. Print("Factorial of ", counter, " => ", value); 19. counter = counter + 1; 20. value = value * counter; 21. } 22. //+------------------------------------------------------------------+
Code 04
Beachten Sie, dass die einzige Änderung zwischen Code 03 und Code 04 das Vorhandensein des reservierten Schlüsselworts static in den Zeilen 15 und 16 ist. Diese einzige Änderung stellt jedoch sicher, dass das Ergebnis bei der Ausführung von Code 04 im MetaTrader 5-Terminal genau dem in Abbildung 01 gezeigten entspricht. Mit anderen Worten: Wir haben den erwarteten Erfolg erzielt. Aufgrund der statischen Natur von Variablen, die als statisch deklariert sind, sollten sie jedoch mit Vorsicht behandelt werden. Das liegt daran, dass es bestimmte Regeln für ihr Verhalten gibt. Sie sind zwar nicht strikt verpflichtet, bestimmte Praktiken zu befolgen, aber es ist wichtig zu verstehen, wie statische Variablen funktionieren, um Probleme zu vermeiden.
Eine statische Variable ist in erster Linie für den Einsatz innerhalb eines Blocks gedacht. Es gibt zwar seltene Situationen, in denen sie außerhalb eines Blocks für spezielle Zwecke verwendet werden können, aber im Allgemeinen sollten Sie statische Variablen als an einen Codeblock gebunden betrachten.
Zweitens sollten Sie, außer in sehr speziellen Anwendungsfällen, niemals eine statische Variable außerhalb ihrer Deklaration initialisieren. Wenn Sie dies unüberlegt tun, können Sie die Kontrolle über Ihren Code verlieren. In diesem einfachen, didaktischen Beispiel mag es sich so anfühlen, als hätten Sie die volle Kontrolle. Lassen Sie sich jedoch nicht davon täuschen, dass dies immer der Fall ist. Ein einziger Fehler oder ein Versehen kann schnell dazu führen, dass man Stunden (oder sogar Tage) mit der Fehlersuche verbringt. Um diesen Punkt zu verdeutlichen, nehmen wir eine kleine Änderung am Code 04 vor und sehen, was passiert. Der aktualisierte Code ist unten abgebildet:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. Factorial(); 07. Factorial(); 08. Factorial(); 09. Factorial(); 10. Factorial(); 11. } 12. //+------------------------------------------------------------------+ 13. void Factorial(void) 14. { 15. static uchar counter; 16. static ulong value = 1; 17. 18. counter = 1; 19. Print("Factorial of ", counter, " => ", value); 20. counter = counter + 1; 21. value = value * counter; 22. } 23. //+------------------------------------------------------------------+
Code 05
Ich füge den vollständigen Code bei, damit Sie die Änderungen genauer verfolgen können. Auf diese Weise können Sie besser verstehen, was passiert, wenn ein kleiner Fehler in einer Anwendung gemacht wird. Achten Sie darauf und vergleichen Sie den Unterschied zwischen Code 04 und Code 05. Auf den ersten Blick mag dies trivial, fast harmlos erscheinen. Etwas, von dem man nicht erwarten würde, dass es sich auf das Ergebnis auswirkt. Bei der Ausführung verwandelt sich die im MetaTrader 5-Terminal angezeigte Abbildung 01 jedoch in etwas völlig anderes, wie in der folgenden Abbildung zu sehen ist:
Abbildung 03
Es ist seltsam. Was eigentlich eine Faktorenberechnung sein sollte, hat sich in eine Zweierpotenzberechnung verwandelt. Wie ist das passiert? Nun, mein lieber Leser, es gibt einen kleinen Trick, um richtig mit statischen Variablen zu arbeiten. Ein erfahrener Programmierer, der mit Code konfrontiert wird, der sich nicht wie erwartet verhält, wird schnell ein Problem mit der Verwendung von Variablen vermuten. Wenn die Sprache statische Variablen zulässt und der Code sie enthält, sollten Sie als erstes überprüfen, ob diese Variablen korrekt initialisiert werden
und ob eine Änderung ihrer Werte zu erwarten ist. Dies sind die ersten zu prüfenden Punkte. Da wir erwarten, dass sich der Wert einer Variablen ändert (sonst würden wir Konstanten verwenden), können wir prüfen, ob sich die Variable ändert und den zuletzt zugewiesenen Wert vergisst. Hierfür gibt es verschiedene Debugging-Techniken. Ich empfehle Ihnen, die Debugging-Methoden im Detail zu studieren, da jede Situation eine etwas andere Herangehensweise erfordern kann.
Aber zurück zu der Frage, warum sich der Code seltsam verhält, obwohl er in Ordnung zu sein scheint. Der erste Gedanke, der mir in den Sinn kommt, ist, dass alles richtig zu sein scheint. Statische Variablen werden jedoch bei ihrer Erstellung initialisiert. Wird diese Initialisierung versäumt, verhält sich die Variable so, als ob sie lokal wäre. Das bedeutet, dass die Variable jedes Mal neu deklariert wird und damit ihr statisches Verhalten verliert. Das bedeutet natürlich, dass das, was in Zeile 18 von Code 05 gezeigt wird, innerhalb des Blocks so weit wie möglich vermieden werden sollte. Dies führt dazu, dass die statische Variable unterbrochen wird und nicht mehr funktioniert. Das ist der Grund für das merkwürdige Verhalten des Codes: Was eine statische Variable war, war nun eine reguläre Variable.
Damit haben wir nun eine gute Grundlage, um die nächsten Punkte in Angriff zu nehmen.
Der Datentyp
Lassen Sie uns nun kurz auf die Datentypen eingehen, da es wichtig ist, Ihnen ein erstes Verständnis für dieses Konzept zu vermitteln. Im weiteren Verlauf werden Sie feststellen, dass es um viel mehr geht.
Dabei geht es um den Datentyp oder den Variablentyp. In vielen Programmiersprachen, insbesondere in Skriptsprachen wie JavaScript und Python, muss der Programmierer den Typ der gespeicherten Daten nicht ausdrücklich angeben. Diese werden als dynamisch typisierte Sprachen bezeichnet. Andererseits sind Sprachen wie C/C++ und MQL5 statisch typisiert. Das bedeutet, dass der Programmierer den in jeder Variablen erwarteten Datentyp angeben muss. Was bedeutet das für die Praxis? In dynamischen Sprachen wie Python kann eine Variable jeden Werttyp enthalten, und die Sprache passt die Variable automatisch an den entsprechenden Typ an. In MQL5 kann eine Variable jedoch nicht jeden beliebigen Wert speichern - sie muss mit einem bestimmten Typ deklariert werden. Dies ist theoretisch, denn es gibt Möglichkeiten, solche Unannehmlichkeiten zu umgehen.
Aber für diejenigen, die in streng typisierten Sprachen programmieren, werden einige Dinge komplizierter, weil es nicht ausreicht, einfach eine Variable zu deklarieren und in sie zu setzen, was immer man will. Hierfür gibt es Regeln und Einschränkungen. In Sprachen wie Python kann eine Variable jedoch einen Text oder sogar einen beliebigen anderen Wert annehmen, und die Sprache legt automatisch den am besten geeigneten Typ für die Variable fest. Dadurch ist die Komplexität der Programmierung deutlich geringer, was die Erstellung von Code viel einfacher und schneller macht und vom Programmierer keine so große Spezialisierung erfordert. Dies unterscheidet sich von statisch typisierten Sprachen, bei denen wir wissen müssen, was jeder Typ enthalten kann und was nicht.
An diesem Punkt könnten Sie darüber nachdenken, MQL5 aufzugeben und sich nach etwas Einfacherem umzusehen, wie Python oder JavaScript. Wenn Sie sich jedoch erst einmal an statisch typisierte Sprachen gewöhnt haben, könnten Sie die Arbeit in dynamisch typisierten Sprachen als weniger interessant empfinden, da sie weniger Nachdenken in Bezug auf die Datenverarbeitung erfordern. Um mit Daten arbeiten zu können, muss man wissen, worum es sich handelt, wie sie in verschiedene Typen eingeteilt werden können und wo die Grenzen der einzelnen Typen liegen. Das Erlernen des Umgangs mit verschiedenen Datentypen eröffnet viele Möglichkeiten, z. B. die Arbeit mit Verschlüsselung oder Datenkompression.
Aber das ist ein Thema für ein anderes Mal. Lassen Sie uns zunächst die Grundlagen der Datentypen in MQL5 behandeln.
In MQL5 gibt es ein paar Grundtypen, die Sie verwenden können: Ganzzahlen, Boolesche Operatoren, Literale, Fließkommazahlen, Enumerationen und Zeichenketten. Sie erscheinen auch in C/C++-Code. Zusätzlich zu diesen Typen, die in vielen C/C++-basierten Sprachen üblich sind, verfügt MQL5 jedoch auch über spezielle Typen wie Farbdaten sowie Datums- und Zeitdaten. Obwohl sie, wie wir später sehen werden, Derivate anderer Arten sind, kann allein die Tatsache ihrer Existenz in bestimmten Fällen nützlich sein.
Komplexe Datentypen gibt es sowohl in C/C++ als auch in MQL5. Dies sind Strukturen und Klassen. Was die Klassen betrifft, so gibt es sie in C++ durchaus. Aber hier in MQL5 sind die Klassen viel einfacher zu verstehen und damit zu arbeiten als in C++. Obwohl ich als C++-Programmierer manchmal einige Klassenressourcen vermisse, die in C++ vorhanden sind, aber in MQL5 nicht existieren. Aber wir passen uns an, damit die Arbeit getan und das Ziel erreicht wird.
Dies ist eine grundlegende Einführung in das Thema, aber wir können später noch mehr ins Detail gehen. Bevor wir diesen Artikel beenden, wollen wir noch kurz auf die Grenzen der Grundtypen eingehen. Wenn Sie die Grenzen der einzelnen Typen kennen, wird Ihnen das bei Ihrer zukünftigen Programmierung sehr helfen. Beginnen wir mit einer einfachen Tabelle, in der die Grenzen dieser Typen aufgeführt sind (siehe unten).
Typ | Anzahl der Bytes | Niedrigster Wert | Höchster Wert |
---|---|---|---|
char | 1 | -128 | 127 |
uchar | 1 | 0 | 255 |
bool | 1 | 0 (False) | 1 (True) |
short | 2 | -32 768 | 32 767 |
ushort | 2 | 0 | 65 535 |
int | 4 | - 2 147 483 648 | 2 147 483 647 |
uint | 4 | 0 | 4 294 967 295 |
color | 4 | -1 | 16 777 215 |
float | 4 | 1.175494351e-38 | 3.402823466e+38 |
long | 8 | -9 223 372 036 854 775 808 | 9 223 372 036 854 775 807 |
ulong | 8 | 0 | 18 446 744 073 709 551 615 |
datetime | 8 | 0 (01/01/1970 00:00:00) | 32 535 244 799 (31/12/3000 23:59:59) |
double | 8 | 2.2250738585072014e-308 | 1.7976931348623158e+308 |
Tabelle der Haupttypen
Diese Tabelle zeigt nur einfache Datentypen. Auf die Analyse komplexer Typen wird hier nicht eingegangen, da wir sie später betrachten werden. Das Verständnis dieser Tabelle der einfachen Typen wird uns jedoch helfen, den am besten geeigneten Typ zu wählen, je nachdem, was wir für unsere Berechnungen benötigen. Das liegt daran, dass jeder Typ eine Unter- und Obergrenze hat, die er darstellen kann.
Es gibt jedoch zwei Elemente in dieser Tabelle, auf die wir in Zukunft näher eingehen werden: die Typen „double“ und „float“. Das liegt daran, dass beide ihre eigenen Merkmale haben, die separat erklärt werden müssen.
Aber lassen Sie uns kurz über diese Tabelle sprechen. Sie können die Ähnlichkeit in den Namen sehen, wo in einigen Fällen der Buchstabe u vor dem Typnamen steht, wie in char und uchar. Der Buchstabe u hat eine besondere Bedeutung: Wenn dieser Buchstabe vor einem Typennamen erscheint, bedeutet dies, dass der Typ bei Null beginnt und bis zu einer bestimmten Grenze geht. Denn dieser Anfangsbuchstabe u kommt von dem Wort „unsigniert“. Aber was bedeutet „ohne Vorzeichen“ in der Praxis? Wenn wir einen Wert ohne Vorzeichen haben, bedeutet dies, dass er immer als positiv interpretiert wird. Wenn ein Wert mit Vorzeichen versehen ist, kann er entweder positiv oder negativ sein. Dies wird deutlicher, wenn wir über mathematische Operationen sprechen. Im Allgemeinen kann dies folgendermaßen interpretiert werden: Wenn wir einen negativen Wert speichern wollen, können wir ihn in einem Typ mit Vorzeichen ablegen. Wenn jedoch alle zu speichernden Werte positiv sind, kann ein Typ ohne Vorzeichen verwendet werden. Aber warum spreche ich über das, was möglich ist? Wäre es nicht richtiger, von dem zu sprechen, was notwendig ist? Eigentlich ist das nicht notwendig. Wir werden dies später, wenn wir über mathematische Operationen sprechen, genauer betrachten. Hier gibt es eine grundlegende Regel: Ganzzahlige Werte, d. h. solche, die keine Fließkommazahlen verwenden, sind exakt. Fließkommazahlen sind nicht exakt. Wenn man sich diese Tabelle ansieht, könnte man meinen, dass es immer besser ist, den Datentyp „double“ zu verwenden, da er einen großen Bereich abdeckt, aber in der Praxis ist das nicht immer der Fall. Ein guter Programmierer muss daher wissen, wie er den richtigen Datentyp auswählt.
Wahrscheinlich sehen Sie sich diese Tabelle an und denken: Wo ist der Typ „string“ für Zeichenketten? Ist das kein Basistyp? Ja, „string“ ist ein Grundtyp. Es handelt sich jedoch um eine besondere Art, die besser in eine andere Kategorie passt, auf die wir später eingehen werden. Aus diesem Grund wird sie in der Tabelle nicht aufgeführt.
Abschließende Überlegungen
In diesem Artikel haben wir hauptsächlich über statische Variablen gesprochen. Wir haben einige Experimente mit ihnen durchgeführt und gezeigt, wie sie verwendet werden können. Der Artikel konzentriert sich auf die Erläuterung einer möglichen Verwendung von statischen Typen, da solche Variablen auch für andere Zwecke verwendet werden können. In der überwiegenden Mehrheit der Fälle, in denen wir auf statische Variablen treffen, werden sie jedoch wie hier gezeigt verwendet. Später werden wir uns andere Möglichkeiten ansehen, statische Variablen für verschiedene Zwecke zu verwenden. Was Sie hier gesehen haben, wird Ihnen helfen, viele Programme zu verstehen und effizientere Lösungen zu implementieren, die nicht von der übermäßigen Verwendung globaler Variablen abhängen.
Sie haben auch eine kurze Einführung in das Thema des nächsten Artikels, nämlich Datentypen, erhalten. Es gibt Unterschiede und Einschränkungen für jeden Datentyp in MQL5, aber wir haben gesehen, warum diese Einschränkungen existieren und wie sie umgangen werden können, um sie für spezifischere Zwecke zu erweitern.
Aber keine Sorge, wir werden es bald sehen. In diesem Sinne komme ich zum Ende dieses Artikels. Ich habe die Codes an den Artikel angehängt, damit Sie mit ihnen experimentieren und Ihre eigenen Schlüsse aus dem hier Erklärten ziehen können. Bis bald
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/15302





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.