Auf Wiedersehen, Roboter - Hallo, Marasmus - Seite 7

 
Renat:
...

Prüfung dieses Beispiels:

  • MQL4/MQL5 - gibt Warnungen über mögliche Fehler

  • Visual Studio 2012, einschließlich Code Analysis - nichts, die Qualität der Analyse für potenzielle Fehler ist gleich Null. Sie machen sich nicht die Mühe, da es lange Zeit keine Konkurrenten gibt.

  • PVS Studio - meldet korrekt.

  • Lint - meldet dasselbe, aber das 'x' versteckt sich...

    ...

Pavlick:

Auch ich halte die Nachrichten für absolut nutzlos. Ich bin kein professioneller Programmierer, aber diese Art von Unsinn in µl stresst mich. Ich frage mich, ob PVS Studio eine Warnung ausgeben wird, wenn die Verweise auf a und b konstant sind (ich habe keine Möglichkeit, dies selbst zu überprüfen)?

Dennoch ist es nicht schlecht, sich zuerst mit dem Kern der Warnung zu befassen und sie dann als Argument vorzubringen. PVS Studio warnt Sie nicht, weil die globale Variable versteckt ist, sondern weil a und b durch eine nicht konstante Referenz übergeben, aber nicht verändert werden. In diesem Fall sind sie der Meinung, dass a und b durch eine konstante Referenz übergeben werden sollten. Bei den folgenden Beispielen beschwert sich der Analysator nicht:

int a=1,b=2;
int sum(const int& a, const int& b){
        return(a+b);
}

int main(){
        return sum(a,b);
}

//-------------------------------------------------
int a=1,b=2;
int sum(int& a, int& b){
        ++a; ++b;
        return(a+b);
}

int main(){
        return sum(a,b);
}
 

Ich bin mir sehr wohl bewusst, was die PVS uns vorwirft.

Noch einmal: Wir tragen nicht die Verantwortung für die Kompilierung von Milliarden von Zeilen alten C/C++-Codes. Es liegt an ihren eigenen Compilern, ihr Geschäft nicht durch Warnungen zu verderben. Wir hingegen tragen die Verantwortung für die Sicherheit und Fehlerkontrolle unserer Anwendungssprache, die mit Geld arbeitet.

Nur wenige Prozent der MQL4/5-Code-Autoren sind professionelle (im wahrsten Sinne des Wortes) Programmierer. Alle anderen sind einfach Autodidakten und haben keine Ahnung, wie schlecht sie Code schreiben.

Nach der Umstellung auf das aktualisierte MQL4 mussten wir zum Beispiel Tausende von Quellen in der kodobase manuell durchpflügen und eine unglaubliche Anzahl von Fehlern in ihrem alten Code beheben. Viele Fehler wurden vom Compiler gefunden und angezeigt, auch ohne dass die Programme ausgeführt wurden.

Deshalb sollten wir nicht behaupten, dass wir Warnungen aussprechen, sondern unseren eigenen Code korrigieren.

 
Renat:

Ich bin mir sehr wohl bewusst, was die PVS uns vorwirft.

Noch einmal: Wir tragen nicht die Verantwortung für die Kompilierung von Milliarden von Zeilen alten C/C++-Codes. Es liegt an ihren eigenen Compilern, ihr Geschäft nicht durch Warnungen zu verderben. Wir hingegen tragen die Verantwortung für die Sicherheit und Fehlerkontrolle unserer Anwendungssprache, die mit Geld arbeitet.

Nur wenige Prozent der MQL4/5-Code-Autoren sind professionelle (im wahrsten Sinne des Wortes) Programmierer. Alle anderen sind einfach Autodidakten und haben keine Ahnung, wie schlecht sie Code schreiben.

Nach der Umstellung auf das aktualisierte MQL4 mussten wir zum Beispiel Tausende von Quellen in der kodobase manuell durchpflügen und eine unglaubliche Anzahl von Fehlern in ihrem alten Code beheben. Viele Fehler wurden vom Compiler gefunden und angezeigt, auch ohne dass die Programme ausgeführt wurden.

Deshalb sollten Sie sich nicht über die Ausgabe von Warnungen beschweren, sondern Ihren Code verbessern.


Wenn das Array es erlaubt, seinen Bereich zu verfehlen, wäre es sehr dumm, beim Schreiben des Indikators selbst einen Aufwand zu betreiben, der mit dem des Schreibens des Indikators vergleichbar ist, sondern nur für die Berechnung des Berechnungsbeginns.

Sie brauchen sich nicht durch diesen Code zu wühlen, die Hälfte davon ist nicht behoben, sondern kaputt. Sie hätten einfach eine zusätzliche Eigenschaft erstellen können, um zwischen altem mql4, neuem mql4 oder neuem mql4 mit strict zu unterscheiden. Welche Größe hat der alte Compiler? Ich weiß es nicht, aber wahrscheinlich weniger als ein Megabyte, was im Zeitalter der Gigabytes kein Problem ist, es mit sich herumzuschleppen. Aber hier haben wir es mit einer Art Heldentat zu tun - der Zerstörung der Codebase.

* * *

Warnung

Die Deklaration von 'a' verdeckt die globale Deklaration in Zeile X

Dies ist eine idiotische Warnung. Wenn jemand in der "höheren" Welt Probleme damit hat, heißt das nicht, dass andere auch solche Probleme haben könnten. Es gibt einen Geltungsbereich für Variablen, und was jemand als Variablen bezeichnet, ist eine private Angelegenheit.

 
Integer:


Wenn ein Array über seinen Bereich hinausgehen darf, wäre es sehr dumm, beim Schreiben des Indikators einen Aufwand zu betreiben, der mit dem des Schreibens des Indikators selbst vergleichbar ist, aber nur den Anfang der Berechnung zu berechnen.

Sie hätten es vermeiden können, sich durch diesen Code zu wühlen, denn die Hälfte davon ist nicht behoben, sondern kaputt. Man hätte einfach eine zusätzliche Eigenschaft erstellen können, um zwischen altem mql4, neuem oder neuem mit strict zu unterscheiden. Welche Größe hat der alte Compiler? Ich weiß es nicht, aber wahrscheinlich weniger als ein Megabyte, was im Zeitalter der Gigabytes kein Problem ist, es mit sich herumzuschleppen. Aber hier ist eine Art heroische Arbeit getan - die Codebasis zu zerstören.

Genau genommen repariert, nicht kaputt.

Wenn sich ein Fehler nach der Bearbeitung eingeschlichen hat, ist das durchaus möglich - jede Bearbeitung führt zwangsläufig zu solchen Fehlern. Das heißt aber nicht, dass man sich einzelne Fehler auf die Fahne schreiben und einen Berg von korrigierten Fehlern erklimmen kann.


Das 'a' verdeckt die globale Deklaration in Zeile X

Dies ist eine idiotische Warnung. Wenn jemand in der "höheren" Welt Probleme damit hat, heißt das nicht, dass andere auch solche Probleme haben. Es gibt einen Bereich der Sichtbarkeit von Variablen, und was jemand als Variablen bezeichnet, ist Privatsache.

Erstaunliche Menschen, die für das Recht kämpfen, selbst zu schießen. Besonders erfreulich ist es, wenn jemand allen Ernstes schreibt: "Lasst den alten Compiler in Ruhe".
 
simpleton:

Ein potenzieller Fehler ist ein potenzieller Fehler, weil er nicht unbedingt ein Fehler ist.

Ich weiß es nicht, ich weiß es nicht. Früher gab es die Faustregel, Haftbefehle der Stufe 4 oder 5 freizugeben und das Kästchen anzukreuzen, um Haftbefehle als Fehler zu zählen.

Wir sind wirklich dumme Warnungen mit Pragmas losgeworden, aber wir sind sie trotzdem losgeworden.

 
Andrei01:

Diese Bemerkung ist sinnlos und liefert dem Programmierer im Prinzip keine nützlichen Informationen, da die Variable "a" nicht, wie behauptet, verborgen wird.

1.cpp(3): remark #3280: declaration hides variable "a" (declared at line 1)
  int sum(int& a, int& b){        

Wenn der Programmierer das Verstecken absichtlich einsetzt, dann ist diese Bemerkung bedeutungslos und liefert keine nützlichen Informationen. Wurde die Unterschlagung hingegen aus Fahrlässigkeit begangen, können wir den Fehler durch die Bemerkung frühzeitig erkennen.

Andrei01:

Das Ausblenden erfolgt nur, wenn eine lokale Kopie der Variablen erstellt wird, was ebenfalls eine völlig legitime Aktion ist. Selbst wenn durch dieses Verstecken plötzlich ein Fehler im Code auftritt, wird er leicht gefunden, weil die Suche sofort den gleichen Namen findet. Wenn wir anfangen, die Namen in einer Funktionsschablone zu ändern, was eine "Lösung" für diese Regel durch die Compilerlogik ist, wird die Fehlersuche viel komplizierter und es wird viel Verwirrung beim Verständnis des Codes geben. Das scheint offensichtlich.

Lokale Variablen und Parameter befinden sich in einem Bereich, so dass es keine Rolle spielt, ob ein Parameter diesen Namen oder eine lokale Variable hat, aber in jedem Fall verbirgt dieser Name einen Namen im äußeren Bereich.

Verstecken hat nichts mit Kopien von Variablen zu tun, sondern mit Entitätsnamen. Ja, auch wenn es sich um Entitätsnamen wie Typen handelt:

class A { };

void f(int a) {
        A x;
}

es kompiliert:

$ icpc -c 1.cpp
$ 

Und dies:

class A { };

void f(int A) {
        A x;
}

Das ist nicht der Fall:

$ icpc -c 1.cpp
1.cpp(4): error: expected a ";"
        A x;
          ^

compilation aborted for 1.cpp (code 2)
$ 

Denn der Name A innerhalb einer Funktion ist nicht mehr ein Typname, sondern ein Variablen-Parametername. Der Name des im äußeren Bereich deklarierten Typs wird nun durch den Namen des Variablen-Parameters verdeckt. Sie können einen indirekten Eindruck davon gewinnen, wenn Sie sehen, dass dieser Code

class A { };

void f(int A) {
        A++;
}

gut kompiliert:

$ icpc -c 1.cpp
$ 

In MQL4++ kompiliert dies bereits beim Verstecken des Typnamens durch den Namen des Variablenparameters nicht, d.h. auch bei einem leeren Funktionskörper:

#property strict

class A { };
void f(int A) { }
void OnStart() { }

Ergebnis:

'A' - structure identifier cannot be used       3.mq4   4       12
'A' - structure identifier cannot be used       3.mq4   4       12

Ich weiß nicht, warum, aber es überrascht mich nicht im Geringsten.

Für C++ hingegen gibt es kein Problem mit solchem Code:

class A { };
void f(int A) { }

Ergebnis eines Kompilierungsversuchs:

$ icpc -c 1.cpp
$ 

Dieses Beispiel zeigt, dass sich das Verstecken auf Entitätsnamen bezieht und nicht auf etwas anderes.

Wenn die Bemerkung nicht umschaltbar ist, müssen wir alles Mögliche erfinden, wie z. B. die Namen zu fälschen. Aber wenn es drehbar ist, wie im Intel-Compiler, haben Sie solche Probleme nicht.

Das Problem in MQL4++ liegt nicht in der Compilerfunktionalität selbst, was die Erkennung von versteckten Namen in verschachtelten Bereichen betrifft, sondern in der grundsätzlichen Unveränderlichkeit dieser Funktionalität.

 
Renat:

Man sollte also keine Behauptungen über die Warnungen aufstellen, sondern seinen eigenen Code korrigieren.

Die Beschwerde über die zur Diskussion stehenden Warnungen/Hinweise kann meiner Meinung nach eine sein - über ihre prinzipielle Nichtausschließbarkeit.

Und natürlich kann man dem Programmierer nicht vorschreiben, was er innerhalb der Sprache zu tun und zu lassen hat.

 

Solche Meldungen (die globale Variablen verstecken) machen in C++ einfach keinen Sinn (mql wurde als C++-ähnlich deklariert, richtig?). Zum Beispiel aus folgendem Grund:

struct S1{
    int val;
};

struct S2{};

template<typename _T>
struct SS : _T{
    int f() {int val; return val;}
};

int main(){
    SS<S1> q1; q1.f();
    SS<S2> q2; q2.f();
}
 
Pavlick:

Solche Meldungen (die globale Variablen verstecken) machen in C++ einfach keinen Sinn (mql wurde als C++-ähnlich deklariert, richtig?). Zum Beispiel aus folgendem Grund:

struct S1{
    int val;
};

struct S2{};

template<typename _T>
struct SS : _T{
    int f() {int val; return val;}
};

int main(){
    SS<S1> q1; q1.f();
    SS<S2> q2; q2.f();
}

C++ wurde hier genommen, weil MQL4++ keine Struktur-/Klassenvorlagen hat - nur Funktionsvorlagen?

Ich bin nicht sicher, ob die Entwickler sich dessen bewusst sind, aber Klassenvorlagen sind auch in MQL4++ möglich, wenn auch mit erheblichen Einschränkungen. Insbesondere kann dieses Beispiel wie folgt auf MQL4++ übertragen werden (auch hier wird ein Parameter anstelle einer lokalen Variable in einer Methode verwendet):

#property strict

struct S1 { };
struct S2 { int val; };

template <typename T>
void f(T &t) {
  struct SS: public T {
    int f(int val) { return val; }
  } ss = {0}; // Переменная типа SS
}

void OnStart() {
  S1 s1; f(s1);
  S2 s2; f(s2);
}

Bei der Kompilierung wird eine einzige Warnung über das Verbergen des Namens eingeblendet:

'3.mq4' 3.mq4   1       1
struct has no members, size assigned to 1 byte  3.mq4   3       8
struct has no members, size assigned to 1 byte  3.mq4   8       10
declaration of 'val' hides member declaration at line 4 3.mq4   9       15
0 error(s), 3 warning(s)                1       4

Wenn die letzte wichtige Zeile in OnStart() auskommentiert wird, verschwindet die Warnung über das Verbergen des Namens.

 
simpleton:

C++ wurde hier genommen, weil es in MQL4++ keine Struktur-/Klassenvorlagen gibt - nur Funktionsvorlagen?

...

Im Allgemeinen ja, aber Sie können auch µl verwenden:

struct S1{
    int val;
};

struct S2{};

#define INSTANTIATE(_Name, _T)          \
    struct _Name : _T                   \
    {                                   \
        int f() {int val; return val;}; \
    }

INSTANTIATE(SS1, S1);
INSTANTIATE(SS2, S2);

void start(){
    SS1 q1; q1.f();
    SS2 q2; q2.f();
}