Range/LRange Checks (POUs CheckRangeSigned, CheckRangeUnsigned, CheckLRangeSigned, CheckLRangeUnsigned)
Funktionen zur Überwachung der Bereichsgrenzen eines Unterbereichstypen
- CheckRangeSigned prüft Unterbereichstypen vom Typ SINT, INT, DINT.
- CheckRangeUnsigned prüft Unterbereichstypen vom Typ BYTE, WORD, DWORD, USINT, UINT, UDINT.
- CheckLRangeSigned prüft Unterbereichstypen vom Typ LINT.
- CheckLRangeUnsigned prüft Unterbereichstypen vom Typ LWORD, ULINT.
Aufgabe dieser Überwachungsfunktionen ist eine angemessene Behandlung von Verletzungen der Bereichsgrenzen. Eine Reaktion auf eine Verletzung kann beispielsweise das Setzen eines Error-Flags oder das Verändern eines Wertes sein. Der Aufruf der Funktionen erfolgt implizit bei der Zuweisung eines Wertes an eine Variable des Unterbereichstyps.
![]() | 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. |
Beim Aufruf werden der Funktion folgende Eingangsparameter übergeben:
- value: Wert, der der Variablen des Unterbereichstyps zugewiesen werden soll.
- lower: Bereichsuntergrenze
- upper: Bereichsobergrenze
Rückgabewert ist der Zuweisungswert selbst, sofern sich dieser im gültigen Bereich befindet. Ansonsten wird je nach Verletzung des Unterbereichs seine Ober- oder Untergrenze zurückgegeben.
Die Zuweisung i := 10*y
wird nun implizit ersetzt durch i := CheckRangeSigned(10*y, -4095, 4095);
Hat y
beispielsweise den Wert "1000", so wird der Variablen i
nicht wie im ursprünglichen Code vorgesehen der Wert "10*1000=10000" zugewiesen, sondern der Wert der Bereichsobergrenze, also "4095".
Dasselbe gilt für die Funktionen CheckRangeUnsigned, CheckLRangeSigned und CheckLRangeUnsigned.
![]() | Steht Ihnen keine Funktion zur Bereichsüberwachung zur Verfügung, so erfolgt während der Laufzeit keine Überprüfung des Unterbereichs bei entsprechenden Variablen. In diesem Fall können Sie einer Variablen eines Unterbereichstyps von DINT/UDINT jeden Wert zwischen -2147483648 und +2147483648 beziehungsweise zwischen 0 und 4294967295 zuweisen. Einer Variablen eines Unterbereichstyps von LINT/ULINT können Sie dann jeden Wert zwischen -- 9223372036854775808 und +9223372036854775807 beziehungsweise zwischen 0 und18446744073709551615 zuweisen. |
![]() | Endlosschleifen Wenn Sie Bereichsüberwachungsfunktionen einbinden, können Endlosschleifen entstehen. Dies ist beispielsweise der Fall, wenn die Zählvariable einer FOR-Schleife vom Unterbereichstyp ist und der Zählbereich der Schleife den definierten Unterbereich verlässt! |
Beispiel für eine Endlosschleife:
VAR
nVar : DINT(0..10000);
...
END_VAR
FOR nVar := 0 TO 10000 DO
...
END_FOR
Das Programm verlässt niemals die FOR-Schleife, da die Überwachungsfunktion CheckRangeSigned verhindert, dass nVar
auf einen Wert größer als 10000 gesetzt wird.
Standardimplementierung der Funktion CheckRangeSigned
Wird einer DINT-Variablen eines vorzeichenbehafteten Unterbereichstyps ein Wert zugewiesen, so bedingt dies einen automatischen Aufruf der Funktion CheckRangeSigned. Die Funktion, welche den Zuweisungswert auf den bei der Variablendeklaration festgesetzten Unterbereich beschränkt, ist standardmäßig wie folgt in ST implementiert:
Deklarationsteil:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckRangeSigned : DINT
VAR_INPUT
value, lower, upper : DINT;
END_VAR
Implementierung:
// Implicitly generated code : Only an Implementation suggestion
{noflow}
IF (value < lower) THEN
CheckRangeSigned := lower;
ELSEIF(value > upper) THEN
CheckRangeSigned := upper;
ELSE
CheckRangeSigned := value;
END_IF
{flow}
Beispiel: Erzeugung eines Core Dumps zur Laufzeit in CheckBounds()
Im Folgenden finden Sie ein Beispiel, bei dem die Funktion CreateCallstackCoreDump() in der Funktion Bound Checks (POU CheckBounds) für implizite Prüfungen aufgerufen wird.
Dadurch können Sie herausfinden, in welcher Codezeile ein möglicher Zugriff außerhalb der gültigen Arraygrenzen stattfindet, ohne die Laufzeit mittels Haltepunktes anzuhalten.
Durch den Aufruf von CreateCallstackCoreDump() innerhalb der entsprechenden IF-Zweige von CheckBounds() wird die Aufrufliste (Call Stack) mit der Position des fehlerhaften Arrayzugriffs während der Laufzeit in einem Core Dump gespeichert und kann für Analysezwecke zu einem passenden Zeitpunkt geladen werden.
Funktion CheckBounds:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper: DINT;
END_VAR
// Implicitly generated code: Only an implementation suggestion
{noflow}
IF index < lower THEN
CreateCallstackCoreDump('CheckBounds_IdxTooLow');
CheckBounds := lower;
ELSIF index > upper THEN
CreateCallstackCoreDump('CheckBounds_ IdxTooHigh');
CheckBounds := upper;
ELSE
CheckBounds := index;
END_IF
Dabei wird beispielsweise ein Core Dump mit dem folgenden Namen erstellt:
Port_851_CallStackDump_CheckBounds_IdxTooLow.2322085807.core
Siehe auch: