Twincat: Wie Array Overflow verhindern?

Beiträge
9
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

beim Programmieren in TwinCAT ist es ja problemlos möglich, z.B. ein Array [1..5] zu erstellen und dann was in Array[7] reinzuschreiben, was dann irgendwas im Speicher überschreibt und zu völlig unvorhersehbarem Verhalten führt. Das würde ich mir gern verhindern.

Wenn auf ein Element außerhalb des Arrays zugegriffen wird, möchte ich am liebsten, dass die SPS sofort im Debugger an der richtigen Stelle anhält. Anderswo würde man dann ein Throw_exception machen, aber das scheint bei SPS unüblich? Ich habe jedenfalls keine Möglichkeit dazu gefunden.

Und nein, ich möchte nicht, dass die SPS in dem Fall weiterläuft. Ich habe einen Prozess, bei dem korrekter Ablauf extrem wichtig ist und den Prozess nach Fehlerbehebung neu zu starten völlig akzeptabel.

Eine Idee für eine Lösung wäre ein Function Block, den ich bei Aufruf eines Arrayelementes nutzen müsste - so nach dem Motto statt

x := aTestarray[15];

zu schreiben

x := aTestarray[fbSafe.M_test(15)]

Das hat aber auch einige Probleme:

  • Es verbessert nicht gerade die Lesbarkeit des Codes
  • Der FB muss für jedes Array einzeln instanziert werden, damit er die richtigen Grenzen hat, was es noch unübersichtlicher macht (also nicht einfach fbSafe.M_test(15), sondern fbSafe_aTestarray.M_test(15)
  • FB und Array müssen beide bei Compilierung angelegt werden; ich kann also nicht den FB nutzen, um die Arraygrenzen zu erzeugen. Die Arraygrenzen kann ich später glaube ich auch nicht mehr aus dem Array auslesen? Das bedeutet, ich muss die Arraygrenzen an zwei verschiedenen Stellen angeben, was wieder fehleranfällig ist.
Wie würdet Ihr das lösen? Hat jemand schon eine Lösung oder Best Practice?
 
Du könntest Dir etwas basteln.
Bei TwinCAT gibt es POUs für implizite Prüfungen. Deren Funktion kannst Du erweitern, die Schnittstelle leider nicht. Vielleicht hilft Dir das etwas.
Nachtrag: Geht es um den Zugriff auf Elemente mit Konstanten, also direkt einer Zahl oder einer als Constant deklarierten Variablen? Das macht der Compiler selber schon und gibt eine Fehlermeldung aus.
 
Zuletzt bearbeitet:
Bei TwinCAT gibt es POUs für implizite Prüfungen.
Danke, Leute, das ist genau das, was ich gesucht habe! Ohne Euch hätte ich das in tausend kalten Wintern nicht gefunden, weil ich nicht wusste, dass es sowas gibt und die Google-Suche nach "Array" niemals bei "POUs für implizite Prüfungen" rauskommen würde.

Ich hab jetzt gedacht, ich nehme die POU CheckBounds rein, und schreibe sie so um, dass ich durch Null teile, wenn ich außerhalb des Ranges bin:

{noflow}
IF index < lower THEN
CheckBounds := 1/0;
ELSIF index > upper THEN
CheckBounds := 1/0;
ELSE
CheckBounds := index;
END_IF
{flow}

Allerdings lässt Twincat mich keinen Code mit so offensichtlicher Division durch 0 kompilieren :rolleyes: Da muss ich mir noch was überlegen...

Ich will, dass das Programm abbricht, weil ich dann offensichtlich einen Denkfehler habe und der am leichtesten zu finden ist, wenn das Programm an der Stelle stehen bleibt.

Eigentlich wären Breakpoints perfekt, aber die haben die Angewohnheit, beim Neukompilieren, Neuladen oder ähnlichem zu verschwinden...
 
Variable e
Allerdings lässt Twincat mich keinen Code mit so offensichtlicher Division durch 0 kompilieren :rolleyes: Da muss ich mir noch was überlegen...
Dem Manne kann geholfen werden. Deklariere einfach eine Variable (Achtung keine Konstante), in dem Fall auch gerne Global, setze den Init-Wert auf 0 und beschreibe Sie nie, nimm diese Variable als Divisor, fertig.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das ist ja interessant.
Wenn Jemand sagen würde, dass ich durch das Teilen durch 0 in TIA bewusst einen Fehler herbeiführen soll, um das Programm besser debuggen zu können, höre ich schon wieder alle schreien, wie schlecht TIA ist, das SIEMENS nur Mist macht und dass das ja in der heutigen Zeit nicht die Lösung sein kann.
 
Der TIA-SCL-Compiler läßt Dich auch nicht durch eine konstante 0 dividieren.
Aber selbst wenn man die Division durch 0 hinkriegt, dann geht eine S7-CPU sowieso nicht in STOP. Da wird noch nichtmal OB121 aufgerufen.

Harald
 
Hinweis zum Checkbounds. Er geht etwas auf die CPU Last. Wenn der Code fertig ist. Sollte CheckBounds wieder entfernt werden
Das ist zu allgemein, die POUs zur impliziten Prüfung sind ja nicht nur zur Nutzung während der Entwicklung gedacht. Man muss halt prüfen, in wie weit einem die Auslastung zu hoch geht.
Die Anweisungen TRY, THROW und CATCH in C++ werden nach der Entwicklung ja auch nicht rausgeworfen.
 
Das ist zu allgemein, die POUs zur impliziten Prüfung sind ja nicht nur zur Nutzung während der Entwicklung gedacht. Man muss halt prüfen, in wie weit einem die Auslastung zu hoch geht.
Die Anweisungen TRY, THROW und CATCH in C++ werden nach der Entwicklung ja auch nicht rausgeworfen.

Das stimmt natürlich. Eigentlich wollte ich nur darauf hinweisen, dass es Auswirkungen auf die Auslastung hat. Woran man erst nicht denkt. Und Falls man Probleme mit einer nicht ausreichend Zykluszeit hat, wäre das Entfernen des CheckBounds eine Möglichkeit,!
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Die Anweisungen TRY, THROW und CATCH in C++ werden nach der Entwicklung ja auch nicht rausgeworfen.

Man kann diese Anweisungen auch im TwinCAT Umfeld verwenden


Diese würden dann nicht so auf die Last gehen. Zumindest meines Wissens.

Da sie nicht implizit sind, sondern - das nenn ich jetzt mal so - explizit!
 
Man kann diese Anweisungen auch im TwinCAT Umfeld verwenden


Diese würden dann nicht so auf die Last gehen. Zumindest meines Wissens.

Da sie nicht implizit sind, sondern - das nenn ich jetzt mal so - explizit!
Stimmt, hatte ich irgendwann auch mal von gelesen, aber wieder vergessen. Allerdings gibt es dabei die Einschränkung, dass es derzeit "nur" bei 32 Bit Zielsystemen läuft.
 
Also danke Euch allen! Ich hab das jetzt genau so gemacht - eine Variable nDivisionByZero : SINT := 0; definiert und wenn ich einen sicheren Abbruch herbeiführen will teile ich durch diese. Also:

Code:
FUNCTION CheckBounds : DINT
VAR_INPUT
    index, lower, upper: DINT;
END_VAR
-------------------------------
Code:
// Implicitly generated code : Only an Implementation suggestion
{noflow}
IF  index < lower THEN
    CheckBounds := 1/nDivisionByZero;
ELSIF  index > upper THEN
    CheckBounds := 1/nDivisionByZero;
ELSE 
    CheckBounds := index;
END_IF
{flow}

Das mit der zusätzlichen Last durch die impliziten Checks habe ich mir auch schon gedacht. Ich refactore aber gerade meinen gesamten Code nochmal und hoffe, dass dann alles so superflott läuft, dass ich sie problemlos drin lassen kann.

Erzeugen die impliziten Checks ungewöhnlich viel Prozessorlast? Ich habe letztens herausgefunden, dass in Methoden definierte Variablen die Ausführung extrem verlangsamen, womit ich gar nicht gerechnet hätte. Ist das bei den impliziten Checks auch so?

Ich bin nicht sicher, ob es bei Software einen Stand "nach der Entwicklung" aber "vor end of life" gibt... Demnach ist es meiner Meinung nach gut, Fehlersuchhilfen wie implizite Checks drin zu lassen.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Bei den impliziten Funktionen ist der Kostenanteil die Anzahl der Instruktionen. Eigentlich nicht viel. Wenn du aber Datacrunching machst und viele Indexe eines Arrays durchläufst summiert es sich.
Worst Case scenario das ich mal gesehen habe: Kostenanteil ca 20% der Gesamtlast. In 08/15 Applikationen fällt es gar nicht auf.
Achja - ich glaube man kann auch exlizit für Codeanteile die impliziten Checks deaktivieren (per Attribut soweit ich mich erinnere).

Bei deinen Methoden/Funktionen ist der Löwenanteil der Kosten das Allokieren der Variabeln auf dem Stack bei jedem Aufruf.
Das kann man bei häufig aufgerufenen Code dann anders gestalten.
Es ist halt manchmal hilfreich wenn man weiss wie die Dampfmaschine denn funktioniert um das eine oder andere "upsala" zu umgehen.

Guga
 
Bei den impliziten Funktionen ist der Kostenanteil die Anzahl der Instruktionen. Eigentlich nicht viel. Wenn du aber Datacrunching machst und viele Indexe eines Arrays durchläufst summiert es sich.
Worst Case scenario das ich mal gesehen habe: Kostenanteil ca 20% der Gesamtlast. In 08/15 Applikationen fällt es gar nicht auf.
Achja - ich glaube man kann auch exlizit für Codeanteile die impliziten Checks deaktivieren (per Attribut soweit ich mich erinnere).

Bei deinen Methoden/Funktionen ist der Löwenanteil der Kosten das Allokieren der Variabeln auf dem Stack bei jedem Aufruf.
Das kann man bei häufig aufgerufenen Code dann anders gestalten.
Es ist halt manchmal hilfreich wenn man weiss wie die Dampfmaschine denn funktioniert um das eine oder andere "upsala" zu umgehen
Super Info. Danke. Leider ist heutige Software nicht mehr ganz so einfach wie eine Dampfmaschine.

Über Dampfmaschine hatte ich ein Referat in der 8 Klasse gehalten und verstehe es, hoffentlich, heute noch
 
Zurück
Oben