Von der Grundstufe bis zur Mittelstufe: Arrays und Zeichenketten (I)
Einführung
Der hier dargestellte Inhalt ist ausschließlich für Bildungszwecke bestimmt. Die Anwendung sollte unter keinen Umständen zu einem anderen Zweck als zum Erlernen und Beherrschen der vorgestellten Konzepte verwendet werden.
Im vorigen Artikel, „Von der Grundstufe zur Mittelstufe: Prioritätsfolge der Operatoren“, haben wir ein wenig über die Vorsichtsmaßnahmen gesprochen, die wir bei der Verwendung von Faktorisierung in unseren Codes beachten sollten. Es ist nicht ungewöhnlich, dass man auf Code stößt, der auf den ersten Blick korrekt erscheint, aber in bestimmten Situationen zu völlig unerwarteten Ergebnissen führt. Diese Art von Problemen hängt oft direkt damit zusammen, wie die Faktorisierungen implementiert werden. Ein Stück Code dazu zu bringen, konsistente Ergebnisse zu liefern, mag wie eine triviale Aufgabe erscheinen. Ohne das entsprechende Wissen (wie in diesem Artikel gezeigt) steigt jedoch die Wahrscheinlichkeit von katastrophalen Fehlern, wenn immer mehr schlecht implementierte Faktorisierungen in den Code eingeführt werden.
Da der theoretische Teil der korrekten Erstellung von Faktorisierungen ziemlich langweilig und mühsam sein kann, werden wir uns nicht weiter damit befassen. Konzentrieren wir uns lieber auf die praktische Seite der Dinge. Deshalb möchte ich Sie, liebe Leser, ermutigen, mit dem mitgelieferten Beispielcode zu experimentieren, wann immer dies möglich ist. Versuchen Sie, die Faktorisierungen zu ändern oder sogar den Kontrollfluss so zu modifizieren, dass er leicht von dem abweicht, was in den beigefügten Dateien dargestellt ist.
Diese Übung ist äußerst wichtig, denn sie hilft Ihnen zu lernen, wie Sie das gleiche Ergebnis auf einem anderen Weg erreichen können, den Sie selbst geschaffen haben. Auch wenn viele dies als Zeitverschwendung ansehen, ist es in Wirklichkeit die effektivste Art zu lernen. Das liegt daran, dass der Anhang Code enthält, der funktioniert und ein gültiges Ergebnis liefert. Ihre Aufgabe ist es, eine andere Version dieses Codes zu entwickeln, die immer noch das gleiche Ergebnis liefert. Mit etwas Übung werden Sie in der Lage sein, Ihre eigenen Lösungen zu entwickeln, auch wenn sie zunächst nicht professionell erscheinen.
Nach dieser kurzen Einführung kommen wir nun zum Hauptthema dieses Artikels. Es gibt eine Voraussetzung, um den Inhalt zu verstehen. Sie sollten bereits ein solides Verständnis für die Deklaration und Verwendung von Variablen und Konstanten haben. Obwohl der Schwerpunkt hier mehr auf Operatoren als auf irgendetwas anderem liegt, ist die Fähigkeit, Variablen und Konstanten zu deklarieren, zu initialisieren und zu verwenden, unerlässlich, um den Erklärungen zu folgen. Hier beginnen wir mit der Erörterung einiger spezieller Datentypen. Ich werde mich bemühen, nicht allein in der Theorie stecken zu bleiben. Dieses Thema ist neben dem Vorrang von Operatoren, den wir im vorigen Artikel behandelt haben, wahrscheinlich eines der komplexeren Gebiete. Wir werden uns dem Thema jedoch zunächst aus einem möglichst einfachen Blickwinkel nähern, um eine klare Vorstellung davon zu bekommen. Dennoch ist dieses Grundwissen notwendig, bevor wir uns in ein noch schwierigeres Thema stürzen. Also, fangen wir an.
Arrays und Zeichenketten
Zweifellos ist dies eines der Themen, die bei neuen Programmierern, die mit statisch typisierten Sprachen arbeiten, die meiste Verwirrung und oft auch Entmutigung hervorrufen. Das liegt daran, dass dynamisch typisierte Sprachen wie Python und JavaScript diese Themen fast transparent behandeln, sodass Programmierer sie verwenden können, ohne sich allzu viele Gedanken über Definitionen oder Strukturen zu machen.
Im Gegensatz dazu machen Sprachen wie C und C++ dieses Thema wesentlich komplexer, da diese beiden Entitäten intern gehandhabt werden. In diesen Sprachen werden Arrays und Strings nicht als unterschiedliche Einheiten behandelt. Je nachdem, wie man mit ihnen arbeitet, kann man sogar auf eine dritte oder sogar vierte Art von Wesen im selben Kontext stoßen. Kurz gesagt, es ist ein komplexes Thema, das für Anfänger schwer zu verstehen ist.
In MQL5 befinden wir uns jedoch auf einem Mittelweg zwischen statisch typisierten Sprachen wie C/C++ und dynamisch typisierten Sprachen wie Python oder JavaScript. Warum sage ich das? Im Gegensatz zu C und C++, wo es oft möglich ist, den Datentyp eines Arrays und in einigen Fällen auch von Strings (Zeichenketten) zu ignorieren, lässt MQL5 diese Art von Flexibilität nicht zu. Zumindest nicht ohne bestimmte Arten der Manipulation. Dadurch wird der Lernprozess etwas vereinfacht. Aber ohne eine solide Grundlage wird es fast unmöglich, bestimmte Arten von Datenmanipulationen in MQL5 durchzuführen, vor allem solche, die man leicht in C oder C++ machen könnte. Allerdings ist es weitaus unwahrscheinlicher, dass Sie als Anfänger etwas in MQL5 schreiben, das Ihnen außer Kontrolle gerät. Anders als in C oder C++, wo schon ein kleiner Fehler zu einer tickenden Zeitbombe werden kann, die beim kleinsten Fehltritt hochgeht.
Aber unter uns gesagt, das Erlernen von MQL5 ist wesentlich einfacher als das Erlernen der gleichen Aufgaben in C oder C++. Deshalb freue ich mich, meine Kenntnisse in C und C++ weiterzugeben und zu übersetzen, um sie für MQL5 nutzbar zu machen. Vielleicht kann ich einigen von Ihnen dabei helfen, ein hohes Maß an Programmierkenntnissen zu erlangen.
Kommen wir nun zum Hauptthema. Lassen Sie uns zunächst eines klarstellen. Arrays und Strings sind in gewissem Sinne dasselbe. Zumindest unter dem Gesichtspunkt, wie Daten im Speicher abgelegt werden. Genauer gesagt, ist eine Zeichenkette nichts anderes als eine spezielle Art von Array. Ich nenne es „speziell“ wegen eines bestimmten Details: Eine Zeichenkette enthält eine Markierung, die anzeigt, wo sie endet. Diese Markierung gibt es in einem normalen Array nicht.
Lassen Sie mich zur Verdeutlichung einen kurzen Vergleich mit anderen Programmiersprachen anstellen. Einige Sprachen, wie z. B. die auf BASIC basierenden (ja, das altmodische BASIC aus der MS-DOS-Ära), speichern die Länge der Zeichenkette in ihrem ersten Zeichen. Dadurch kann jedes beliebige Zeichen innerhalb der Zeichenkette verwendet werden, da die Länge explizit im Voraus angegeben wird. Dieses erste Zeichen, das mehr als ein Byte belegen kann, wird nie angezeigt. Sie bleibt für den Nutzer unsichtbar und ist nur über den Code zugänglich. Diese Methode gibt Ihnen die Freiheit, jedes Zeichen oder jeden numerischen Wert innerhalb der Zeichenkette zu verwenden. Allerdings wird die maximale Länge der Zeichenkette auf die Bitbreite des Anfangszeichens begrenzt.
C- und C++-basierte Sprachen verwenden einen anderen Ansatz. In diesen Sprachen wird ein spezielles Zeichen oder ein Wert verwendet, um anzuzeigen, wo die Zeichenkette endet. Das Konzept eines Strings als nativer Datentyp existiert in C oder C++ nicht wirklich. In der Regel wird ein Nullwert als Abschlusszeichen verwendet. Wenn dieser Wert in der Sequenz erscheint, markiert er das Ende der Zeichenkette. Auf der einen Seite können Sie mit diesem Ansatz eine Zeichenkette erstellen, die praktisch den gesamten verfügbaren Speicher belegen kann. Andererseits bedeutet es, dass Sie das Null-Zeichen nicht im Inhalt der Zeichenkette verwenden können.
Da MQL5 auf C und C++ basiert, folgt es der gleichen Logik. Anders als in C und C++ enthält MQL5 jedoch einen String-Typ. Folglich können wir nicht immer nur Zeichenketten manipulieren. In diesen Fällen wäre die Verwendung eines Arrays sinnvoller. Dies führt natürlich zu weiteren Problemen. Glücklicherweise ist die MQL5-Bibliothek robust genug, um für die meisten dieser Probleme Abhilfe zu schaffen. Einige sind einfach, andere sind komplexer.
Warum erkläre ich das alles? Der Grund dafür ist einfach: Wenn Sie nicht genau wissen, wie Strings und Arrays modelliert werden, sind Sie auf eine begrenzte Anzahl von Optionen beschränkt und können bestimmte Aufgaben nicht ausführen. Insbesondere fortgeschrittene Programmiervorgänge. Es ist nicht ungewöhnlich, dass sich Leute darüber beschweren, dass „man dies oder jenes in MQL5 nicht tun kann“. Aber wenn man tiefer gräbt, stellt man oft fest, dass diese Programmierer in einem begrenzten konzeptionellen Rahmen feststecken, der sie daran hindert, über die grundlegenden Angebote der Standardbibliothek hinauszugehen.
Es ist nicht so, dass die Verwendung der Standardbibliothek einen Mangel an Wissen widerspiegelt. Das Gegenteil ist der Fall. Aber wenn Sie nicht verstehen, wie die Dinge wirklich zusammenhängen, werden Sie sich ständig darüber beschweren, dass bestimmte Dinge nicht möglich sind.
Verstehen Sie also, lieber Leser, Folgendes: Arrays können als eine Art generische Zeichenkette betrachtet werden, die praktisch alles aufnehmen kann. Eine Zeichenkette hingegen ist ein eingeschränkteres Konstrukt, das mit Einschränkungen und manchmal auch ganz ohne Einschränkungen einhergeht. Wenn Sie wirklich etwas bauen wollen, sich aber der Einschränkungen, die durch Arrays oder Strings auferlegt werden, nicht bewusst sind, werden Sie einfach nicht in der Lage sein, es zu tun. Einer der Gründe, warum Arrays etwas schwierig zu beherrschen sind, ist, dass eine Zeichenkette im Wesentlichen ein Array des Typs uchar oder ushort ist, je nach der verwendeten Zeichenkodierung. Ein reines Array kann jedoch von jedem Typ sein: von einer Klasse bis Boolean. Das macht die Sache für Anfänger zweifellos komplizierter. Da ich Ihnen aber einen praktischen Weg aufzeigen möchte, beginnen wir mit der einfachsten Variante. Beginnen wir also mit den Zeichenketten.
Daten vom Typ String
Wenn wir eine Variable als String (Zeichenkette) erstellen oder deklarieren, weisen wir den Compiler im Wesentlichen an, ein Array zu erstellen. Dies ist eine besondere Art von Array, das ein Zeichen oder einen Wert enthält, um anzuzeigen, wo die Zeichenkette endet. Wenn wir eine String-Variable verwenden, müssen wir die Speicherzuweisung nicht manuell verwalten. Das wird vom System automatisch gehandhabt, je nachdem, ob mehr oder weniger Speicher benötigt wird.
So können wir eine Vielzahl von Dingen tun, ohne uns allzu große Sorgen zu machen. Andererseits gibt es auch einige Einschränkungen, aber darüber wollen wir uns vorerst nicht den Kopf zerbrechen. Konzentrieren wir uns auf das, was getan werden kann. Denken Sie daran, dass wahre Meisterschaft nur durch beständiges Üben erreicht wird. Wir werden hier nur an der Oberfläche kratzen. Beginnen wir also mit unserem ersten Stück Code, das unten gezeigt wird:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. string sz0 = "Hello world !!!", 07. sz1 = "My first operation with strings...", 08. sz2; 09. 10. sz2 = sz0 + sz1; 11. 12. Print(sz2); 13. } 14. //+------------------------------------------------------------------+
Code 01
Passen Sie jetzt gut auf, liebe Leserin, lieber Leser. Hier werden drei String-Variablen erstellt. Zwei davon werden bei der Erstellung deklariert und initialisiert. Der dritte erhält das Ergebnis der Kombination der beiden anderen, wodurch eine neue Zeichenfolge entsteht. In Zeile 12 wird das Ergebnis einfach auf dem Terminal ausgegeben, wie unten gezeigt:

Abbildung 01
Das wichtigste Detail dabei ist folgendes: Beachten Sie, dass wir in Zeile 10 den Additionsoperator (+) verwenden. Dies ist einer der wenigen (wenn nicht sogar der einzige) Operatoren, der standardmäßig eine definierte Operation an Zeichenketten durchführt. In diesem Fall wird eine Zeichenkette mit einer anderen verkettet. Seien Sie jedoch sehr vorsichtig mit dieser Art von Konzept, denn die Operatoren verhalten sich nicht immer so, wie man es erwarten würde, insbesondere wenn sie mit verschiedenen Datentypen verwendet werden. Aber wir werden dieses Thema später noch ausführlicher behandeln. Seien Sie einfach vorsichtig, wenn Sie mit Code arbeiten, mit dem Sie nicht vertraut sind.
Wir haben also einen Satz, der im Terminal angezeigt wird. Was aber, wenn wir sie in mehrere Zeilen aufteilen wollen? Wie würden wir das tun? Eine Möglichkeit wäre, zwei separate Print-Anweisungen zu verwenden. Wenn Sie jedoch einen Zeilenumbruch direkt in die Zeichenkette einfügen möchten, können Sie dies mit bestimmten Sonderzeichen tun.
Es gibt verschiedene Sonderzeichen, die in einer Zeichenkette enthalten sein können. Alle von ihnen - zumindest die in MQL5 unterstützten - sind von C/C++ abgeleitet. Wenn Sie also an einer bestimmten Stelle einen Zeilenumbruch einfügen wollen, müssen Sie nur etwas wie das hier einfügen:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. string sz0 = "Hello world !!!", 07. sz1 = "My first operation with strings...", 08. sz2; 09. 10. sz2 = sz0 + "\n" + sz1; 11. 12. Print(sz2); 13. } 14. //+------------------------------------------------------------------+
Code 02
Hier haben wir ein Beispiel für die Verwendung eines solchen Sonderzeichens. Diese Markierungen, wie "\n", werden allgemein als Escape-Sequenzen bezeichnet. Wenn Sie ein wenig recherchieren, werden Sie viele dieser kleinen Codes finden. Wenn Sie eine Escape-Sequenz in eine Zeichenkette einfügen, ändert sich die Ausgabe, wodurch wir Ergebnisse wie das unten gezeigte erzielen können:

Abbildung 02
Doch damit ist das Thema der Escape-Sequenzen noch nicht zu Ende. Zum Beispiel können wir eine Zeichenkette durch Verwendung einer NULL-Zeicxhens abschneiden, wie im folgenden Beispiel zu sehen ist:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. string sz0 = "Hello world !!!", 07. sz1 = "My first operation \0with strings...", 08. sz2; 09. 10. sz2 = sz0 + "\n" + sz1; 11. 12. Print(sz2); 13. } 14. //+------------------------------------------------------------------+
Code 03
Wenn dieser Code 03 ausgeführt wird, zeigt das MetaTrader 5-Terminal die folgende Ausgabe an:

Abbildung 03
Beachten Sie, wie leicht und einfach dies ist. Darüber hinaus können wir aber auch Zeichenketten erstellen, die numerische Werte enthalten. In solchen Fällen müssen wir auf Funktionen aus der MQL5-Standardbibliothek zurückgreifen, um die Konvertierung einfacher und effizienter zu gestalten. Vielleicht zeige ich Ihnen irgendwann in der Zukunft, wie Sie Ihre eigene Version für einen ähnlichen Zweck bauen können. Aber das ist ein Thema für ein anderes Mal. Mit den eingebauten Konvertierungsfunktionen in MQL5 können wir Zahlen in Zeichenketten und Zeichenketten zurück in Zahlen konvertieren.
Diese Funktionalität ist unglaublich nützlich und oft unerlässlich, insbesondere beim Aufbau von Datenanalysesystemen. Ein einfaches Beispiel ist unten dargestellt.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 65538; 07. double d_value = 0.25; 08. color cor = clrRed; 09. string sz0; 10. 11. sz0 = "Color: " + ColorToString(cor) + "\nInteger: " + IntegerToString(i_value) + "\nDouble: " + DoubleToString(d_value); 12. 13. Print(sz0); 14. } 15. //+------------------------------------------------------------------+
Code 04
Wenn Sie den Code 04 ausführen, erhalten Sie eine Ausgabe ähnlich der unten abgebildeten:

Abbildung 04
Beachten Sie, dass wir eine Zeichenkette erstellen konnten, die verschiedene Informationen enthält. In manchen Fällen muss die von uns erstellte Zeichenkette jedoch einem ganz bestimmten Format entsprechen. Dies kann auf die Art der Informationen, mit denen wir arbeiten, oder auf die Formatierungsanforderungen der Daten selbst zurückzuführen sein. In solchen Szenarien müssen wir die Dinge etwas anders angehen, als wir es bisher getan haben. Angesichts der Art dessen, was als Nächstes kommt, halte ich es für das Beste, dies in ein neues Thema auszugliedern. Auf diese Weise wird es für Sie einfacher sein, das hier vorgestellte Wissen zu studieren und anzuwenden.
Formatierung von Zeichenketten
Wenn wir über Textformatierung sprechen, denken viele Menschen sofort an Textverarbeitungsprogramme. Aber in der Programmierung bezieht sich die Formatierung auf die Notwendigkeit, dass bestimmte Informationen bestimmte Kriterien erfüllen müssen, oft bevor sie überhaupt verwendet oder angezeigt werden.
Diese Kriterien machen die Formatierung von Zeichenketten aus. Auf den ersten Blick scheint dies relativ einfach und leicht umsetzbar zu sein. Es ermöglicht, auf relativ einfache Weise Zeichenketten mit sehr spezifischen Inhalten zu erstellen. Es gibt jedoch ein paar wichtige Überlegungen, die Sie als Programmierer beachten müssen. Eines dieser Details betrifft die Konstruktion und Verwendung von Ausgabeparametern. Wenn sie richtig konfiguriert sind, können diese Parameter selbst für Programmieranfänger eine große Erleichterung darstellen, da sie die manuelle String-Konstruktion, die wir im vorherigen Thema verwendet haben, weitgehend ersetzen. Gleichzeitig bieten sie eine große Flexibilität bei der Formatierung unserer Ausgabe und ermöglichen es uns, Strings mit präzisen Strukturen zu erstellen.
Vielleicht haben Sie die Verwendung der Funktion PrintFormat bereits in einigem Code gesehen. Mit dieser Funktion können wir formatierte Ausgaben im MetaTrader 5 Terminal als Zeichenkette anzeigen. Es gibt jedoch Fälle, in denen wir diese Ausgabe nicht direkt an das Terminal senden wollen oder es einfach nicht geeignet ist. In vielen Fällen möchten wir die formatierten Daten in einer Datei speichern oder sie in einem grafischen Objekt in einem Chart verwenden. In solchen Situationen ist PrintFormat nicht immer das richtige Werkzeug. Glücklicherweise bietet MQL5 eine andere Funktion, die für diese Anwendungsfälle viel besser geeignet ist: StringFormat.
Die Funktion StringFormat verwendet die gleiche Parameterstruktur wie PrintFormat. Im Gegensatz zu PrintFormat wird die Ausgabe jedoch als String zurückgegeben. Das macht ihn in einer Vielzahl von Situationen äußerst nützlich.
Wir können also die Ausgabelogik aus Code 04 nehmen und sie anpassen, um eine formatierte Zeichenfolge zu erzeugen. Ich verstehe, dass in diesem Stadium einige der Parameter etwas verwirrend sein könnten. Ich empfehle Ihnen daher, sich die Zeit zu nehmen, jeden Parameter sorgfältig zu prüfen. Lesen Sie die offizielle Dokumentation für die Funktion PrintFormat. Sie enthält detaillierte Informationen zu jeder Formatierungsoption und zur Strukturierung der gewünschten Zeichenkettenausgabe. Um dies zu veranschaulichen, ändern wir Code 04, um die Formatierung von Zeichenketten einzubeziehen. Daraus ergibt sich die unten dargestellte Version:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 65538; 07. double d_value = 0.25; 08. color cor = clrRed; 09. string sz0; 10. 11. sz0 = StringFormat("Color: %s\nInteger: %d\nDouble : %.2f", ColorToString(cor), i_value, d_value); 12. 13. Print(sz0); 14. } 15. //+------------------------------------------------------------------+
Code 05
Wenn Sie Code 05 ausführen, sehen Sie im MetaTrader 5-Terminal ein Ergebnis ähnlich der folgenden Abbildung:

Abbildung 05
Betrachten Sie die Unterschiede zwischen Abbildung 04 und Abbildung 05. Obwohl beide Beispiele sehr ähnlichen Code verwenden, erscheinen die in Abbildung 05 angezeigten Informationen in einem Format, das in unserem Code ausdrücklich definiert wurde, und zwar bei der Implementierung von Zeile 11. Nun könnte man einwenden, dass eine solche Formatierung in diesem Fall nicht wirklich notwendig ist. Bedenken Sie jedoch, dass Sie irgendwann mit hexadezimalen Werten arbeiten werden. Viele Programme verwenden solche Werte, vor allem wenn sie mit bitweisen Operationen arbeiten. Wenn Sie in diesen Szenarien diese Werte visualisieren möchten, um sicherzustellen, dass alles wie erwartet funktioniert, wie machen Sie das?
Nun, das kommt darauf an. Aber im Allgemeinen kann der in Code 05 gezeigte Formatierungsansatz für die Anzeige von Hexadezimalwerten sehr nützlich sein. Manche würden sogar sagen, dass es sich lohnt, ein eigenes Stück Code nur für diesen Zweck zu schreiben. Meiner Meinung nach geht es dabei aber eher um persönliche Befriedigung als um tatsächliche Notwendigkeit. In jedem Fall ist jeder Programmierer frei, seine eigenen Entscheidungen zu treffen. Da Sie aber noch am Anfang der Programmierung stehen, empfehle ich Ihnen, sich an die Funktionen und Prozeduren der Standardbibliothek zu halten. In diesem Fall bedeutet das, dass Sie die Funktion StringFormat verwenden, um eine hexadezimale Darstellung von Werten zu erstellen, die Sie später anzeigen möchten. Dazu verwenden wir weiterhin Code 05, ändern aber die Formatierung der Zeichenketten, die für die Ausgabe verwendet werden. Glücklicherweise ist dies sehr einfach und direkt: Sie müssen nur die Zeile 11 durch die unten stehende Version ersetzen.
sz0 = StringFormat("Color: 0x%X\nInteger: 0x%X\nDouble : %.2f", cor, i_value, d_value);
Wenn Sie diesen geänderten Code ausführen, erhalten Sie die folgende Ausgabe:

Abbildung 06
Interessant, nicht wahr? Aber wir sind hier auf ein kleines Problem gestoßen. Und genau aus diesem Grund habe ich bereits erwähnt, dass Sie bei der Formatierung von Zeichenketten auf die Details achten müssen. Das Problem liegt in diesem Fall beim Farbwert. Beachten Sie, dass sie im hexadezimalen Format angezeigt wird. Der in Abbildung 06 gezeigte Wert steht jedoch nicht unbedingt für die Farbe Rot. Es könnte sogar für etwas ganz anderes stehen. Denken Sie daran, dass Farbwerte in der Regel als RGB oder manchmal auch als ARGB formatiert sind. Es kann also schwierig sein, anhand des Hexadezimalwerts zu erkennen, was er wirklich bedeutet. Aber mit einer kleinen Anpassung können wir die Ausgabe so verändern, dass sie intuitiver und für den Menschen lesbar ist. Ändern Sie dazu einfach den Code wie unten gezeigt:
sz0 = StringFormat("Color: 0x%06X\nInteger: 0x%X\nDouble : %.2f", cor, i_value, d_value);
Wenn Sie den Code mit dieser neuen Änderung ausführen, wird das Ergebnis etwa so aussehen:

Abbildung 07
Warten Sie! Das ist definitiv nicht rot. Was hier erscheint, ist blau. Was ist hier also los? Könnte das Problem darin bestehen, dass wir dem Wert Nullen vorangestellt haben, um einem bestimmten Format zu entsprechen? Und das bringt die Sache irgendwie durcheinander? Nun, ja und nein. Was hier wirklich passiert, ist ein bisschen subtiler. Um es richtig zu erklären, müssen wir ein anderes Beispiel zeigen, das dasselbe Formatierungskonzept verwendet, aber auf eine andere Art von Wert angewendet wird.
Ändern wir den Wert der Variablen i_value und bitten wir das Programm, ihn so zu formatieren, wie wir die Farbe formatiert haben. Das heißt, je nach dem angezeigten Wert können führende Nullen vorhanden sein. Das folgende Beispiel soll dies verdeutlichen:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 0xF; 07. double d_value = 0.25; 08. color cor = clrRed; 09. string sz0; 10. 11. sz0 = StringFormat("Color :\t0x%06X\t=>\t%s\n" + 12. "Integer:\t0x%06X\t=>\t%d\n" + 13. "Double :\t%.2f", cor, ColorToString(cor), i_value, i_value, d_value); 14. 15. Print(sz0); 16. } 17. //+------------------------------------------------------------------+
Code 06
Wenn wir Code 06 ausführen, sehen wir etwa so aus:

Abbildung 08
Hier habe ich die Ausgabe so strukturiert, dass Sie leichter verstehen können, was ich zu demonstrieren versuche. Beachten Sie, dass wir in den Zeilen 11 und 12 des Codes zwei Werte ausgeben. Dies geschieht, um visuell zu verdeutlichen, warum der hexadezimale Farbwert so dargestellt wird, wie er dargestellt wird. Wie Sie sehen können, scheint das Ergebnis von i_value völlig in Ordnung zu sein. Ändern wir nun i_value in eine größere Zahl. Sobald Sie dies tun (wie in der nächsten Version des Codes gezeigt), bleibt die Ausgabe konsistent, wie Sie in der nächsten Abbildung sehen werden:
int i_value = 0xDA09F;

Abbildung 09
Also ja, die Formatierung funktioniert perfekt. Aber warum wird der Farbwert nicht korrekt in hexadezimaler Form angezeigt? Denn auch wenn wir oft erwarten, dass Farbwerte dem RGB-Format folgen, werden sie intern im BGR-Format gespeichert. Das bedeutet, dass die Reihenfolge der Bytes vertauscht ist. Auch wenn der Wert im Hex-Feld falsch aussieht, ist er korrekt. Können wir das ändern, damit die Ausgabe dem intuitiveren Format entspricht? Ja, wir können es schaffen. Und mit dem Wissen aus den vorangegangenen Beispielen ist es eigentlich ganz einfach, diese Anpassung vorzunehmen. Der überarbeitete Code, mit dem dies erreicht wird, ist nachstehend aufgeführt:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 0xDA09F; 07. double d_value = 0.25; 08. color cor = clrRoyalBlue; 09. string sz0; 10. 11. sz0 = StringFormat("Color :\t0x%06X\t=>\t%s\n" + 12. "Integer:\t0x%06X\t=>\t%d\n" + 13. "Double :\t%.2f", cor, ColorToString(cor), i_value, i_value, d_value); 14. 15. Print(sz0); 16. PrintFormat("Color value in hexadecimal (RGB format): %s", ColorToStrHex(cor)); 17. } 18. //+------------------------------------------------------------------+ 19. string ColorToStrHex(const color arg) 20. { 21. return StringFormat("0x%02X%02X%02X", (arg & 0xFF), ((arg >> 8) & 0xFF), (arg >> 16) & 0xFF); 22. } 23. //+------------------------------------------------------------------+
Code 07
Beachten Sie, dass wir in Zeile 19 eine kleine Funktion definieren. Diese Funktion ist auf der Grundlage der in meinen früheren Artikeln vorgestellten Konzepte recht einfach zu verstehen. Wenn wir sie ausführen, gibt die Funktion eine hexadezimale Zeichenfolge zurück. Der zurückgegebene Wert entspricht nun jedoch dem erwarteten RGB-Format, wenn wir Farbwerte analysieren. Wenn Sie den Code 07 ausführen, erhalten Sie eine Ausgabe, die der in Abbildung 10 ähnelt.

Abbildung 10
Jetzt kommt etwas Interessantes. In der ersten Zeile von Abbildung 10 wird der Farbwert im hexadezimalen Format angezeigt. Aber dieser Wert entspricht nicht dem, was wir erwartet haben. Wenn Sie jedoch einen Blick auf die letzte Zeile desselben Bildes werfen, werden Sie genau den Wert finden, den wir erwartet haben, vorausgesetzt, die Farbe wird als RGB gelesen. Die Werte, die Sie in der ersten Zeile sehen, sind in der Byte-Reihenfolge vertauscht, aber wir können sie umdrehen, damit das Ergebnis im erwarteten Format erscheint. Wichtiger Hinweis: Der in der letzten Zeile von Abbildung 10 angezeigte Wert entspricht nicht der tatsächlichen Farbe, die in Zeile 8 von Code 07 definiert wurde. Die formatierte Zeichenkette hier zeigt einfach, wie die Funktion ColorToString die Bytes für eine korrekte Darstellung neu anordnet. Machen Sie sich also keine Sorgen. Ich habe den Farbwert geändert, um sicherzustellen, dass die Erklärung visuell und logisch sinnvoll ist.
Abschließende Überlegungen
In diesem Artikel haben wir den ersten Teil eines Themas vorgestellt, das viel tiefer und fortgeschrittener ist, als es auf den ersten Blick erscheinen mag. Ich verstehe, dass einige Leserinnen und Leser durch die heutigen Erklärungen ein wenig verwirrt sein könnten. Aber ich versichere Ihnen, dass Sie, wenn Sie sich die Zeit nehmen, diese sorgfältig zu prüfen und zu üben, schon bald in der Lage sein werden, sehr nützliche und leistungsstarke Anwendungen im Hinblick auf die Nutzerkommunikation zu entwickeln.
Auch wenn das, was wir heute erforscht haben, nur an der Oberfläche der Möglichkeiten kratzt, so haben Sie doch bereits eine Menge Material, das Sie studieren und in Ihren Projekten anwenden können. Im nächsten Artikel werden wir etwas tiefer in die fortgeschrittene Formatierung und den Umgang mit dem Speicher eintauchen, was für die Erläuterung zukünftiger Themen wichtig sein wird. Bis dahin viel Spaß mit den beigefügten Dateien und üben Sie, was Sie gelernt haben. Wir sehen uns im nächsten Artikel!
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/15441
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Neuronale Netze im Handel: Superpoint Transformer (SPFormer)
African Buffalo Optimierung (ABO)
Wirtschaftsprognosen: Erkunden des Potenzials von Python
Entwicklung eines Replay-Systems (Teil 66): Abspielen des Dienstes (VII)
- 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.