Bound Checks (POU CheckBounds)
Funktionen zur Überprüfung der Feldgrenzen: CheckBounds
Aufgabe dieser Überwachungsfunktion ist eine angemessene Behandlung von Verletzungen von Feldgrenzen. Eine Reaktion auf eine Verletzung kann beispielsweise das Setzen eines Error-Flags oder das Verändern des Arrayindex sein. Die Prüfung erfolgt nur bei einem variablen Arrayindex. Ein fehlerhafter konstanter Arrayindex führt zu einem Compilerfehler. TwinCAT ruft die Funktion implizit auf, sobald einer Variablen vom Typ ARRAY Werte zugewiesen werden.
Nach dem Einfügen der Funktion erhalten Sie automatisch erzeugten Code im Deklarationsteil und Implementierungsteil.
Deklarationsteil nicht verändern Um die Funktionalität der Überwachungsfunktionen zu erhalten, dürfen Sie den Deklarationsteil nicht verändern. Als einzige Ausnahme dürfen Sie lokale Variablen hinzufügen. |
Standardimplementierung
Deklarationsteil:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper: DINT;
END_VAR
Implementierungsteil:
// Implicitly generated code : Only an Implementation suggestion
{noflow}
IF index < lower THEN
CheckBounds := lower;
ELSIF index > upper THEN
CheckBounds := upper;
ELSE
CheckBounds := index;
END_IF
{flow}
Beim Aufruf erhält die Funktion folgende Eingangsparameter:
- index: Index des Arrayelementes
- lower: Untergrenze des Arraybereichs
- upper: Obergrenze des Arraybereichs
Rückgabewert ist der Index des Arrayelements, sofern sich dieser im gültigen Bereich befindet. Ansonsten gibt TwinCAT je nach Verletzung des Grenzbereichs die Ober- oder Untergrenze zurück.
Beispielimplementierung
Deklarationsteil:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper: DINT;
END_VAR
// User defined local variables
VAR
sMessageLow : STRING := 'CheckBounds: Index too low (%d)';
sMessageHigh : STRING := 'CheckBounds: Index too high (%d)';
END_VAR
Implementierungsteil:
{noflow}
// Index too low
IF index < lower THEN
CheckBounds := lower;
// Increase global counter
GVL_CheckBounds.nTooLow := GVL_CheckBounds.nTooLow + 1;
// Log message
ADSLOGDINT(msgCtrlMask := ADSLOG_MSGTYPE_WARN,
msgFmtStr := sMessageLow,
dintArg := index);
// Index too high
ELSIF index > upper THEN
CheckBounds := upper;
// Increase global counter
GVL_CheckBounds.nTooHigh := GVL_CheckBounds.nTooHigh + 1;
// Log message
ADSLOGDINT(msgCtrlMask := ADSLOG_MSGTYPE_WARN,
msgFmtStr := sMessageHigh,
dintArg := index);
// Index OK
ELSE
CheckBounds := index;
END_IF
{flow}
Wie in der Standardimplementierung wird in dieser Beispielimplementierung eine Verletzung des Arraybereichs korrigiert, indem die Ober- oder Untergrenze zurückgegeben wird. Zusätzlich dazu wird jeweils ein globaler Zähler hochgezählt, wenn außerhalb des definierten Arraybereichs auf das Array zugegriffen wird. Die globalen Zähler repräsentieren somit projektweit die Anzahl der Verletzungen der Ober- bzw. Untergrenze. Des Weiteren wird die Funktion ADSLOGDINT aus der Tc2_System-Bibliothek verwendet, um eine Verletzung der Arraygrenzen als Warnung im Meldungsfenster auszugeben.
Anwendungsbeispiel
Im unten stehenden Programm überschreitet der Index die definierte Obergrenze des Feldes aSample. Die CheckBounds-Funktion korrigiert diesen Zugriff auf das Array, welcher außerhalb der definierten Arraygrenzen stattfindet.
PROGRAM MAIN
VAR
aSample : ARRAY[0..7] OF BOOL;
nIndex : INT := 10;
END_VAR
aSample[nIndex] := TRUE;
Die Funktion CheckBounds bewirkt in diesem Beispiel, dass der Index 10 in die Obergrenze des Arraybereichs von aSample (7) abgeändert wird. Damit wird der Wert TRUE dem Element aSample[7] zugewiesen. Auf diese Weise korrigiert die Funktion Arrayzugriffe außerhalb des gültigen Feldbereichs. Es sollte aber unbedingt auch die Fehlerursache, nämlich der Zugriff auf das Element an der Stelle 10, korrigiert werden. Damit dieser automatisch korrigierte, fehlerhafte Zugriff nicht unentdeckt bleibt, wird in diesem Beispiel, wie oben beschrieben, eine Warnung im Meldungsfenster ausgegeben.
Implementierungsbeispiel zur Klassifizierung von Fehlern/Ausnahmen
Globale Variablenliste „GVL_Exc“:
VAR_GLOBAL
nCheckBounds : INT;
nCheckBounds_OutOfBounds : INT;
myException : __SYSTEM.ExceptionCode;
END_VAR
Funktion „CheckBounds“:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper : DINT;
END_VAR
// Only an implementation suggestion
{noflow}
GVL_Exc.nCheckBounds := GVL_Exc.nCheckBounds + 1;
// Index too low
IF index < lower THEN
CheckBounds := lower;
GVL_Exc.myException := __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS;
GVL_Exc.nCheckBounds_OutOfBounds := GVL_Exc.nCheckBounds_OutOfBounds + 1;
// Index too high
ELSIF index > upper THEN
CheckBounds := upper;
GVL_Exc.myException := __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS;
GVL_Exc.nCheckBounds_OutOfBounds := GVL_Exc.nCheckBounds_OutOfBounds + 1;
// Index OK
ELSE
CheckBounds := index;
END_IF
Siehe auch: