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.

Bound Checks (POU CheckBounds) 1:

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:

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: