Pointer, Referenzen, Interfaces
Themenpunkte:
Temporäre Existenz von Pointern/Referenzen/Interfaces auf temporär existierende Objekte
Pointer, Referenzen oder Interfaces, die auf temporär existierende Objekte verweisen, sollten nur so lange wie die Objekte selbst existieren.
Objekte existieren beispielsweise temporär, wenn sie in Methoden oder Funktionen oder als VAR_TEMP instanziiert werden.
Static Analysis:
Überprüfen mit Hilfe von Static Analysis Regel:
Negatives Beispiel:
FUNCTION_BLOCK FB_Sample_neg
VAR
pPointerToSample : POINTER TO ST_Sample; // Sample pointer to a structure
END_VAR
METHOD PUBLIC nccl_TestMethod
VAR
stSample : ST_Sample;
END_VAR
--------------------------------------------------------------------
pPointerToSample := ADR(stSample);
// NON COMPLIANT: stSample is declared in an inner scope. So pPointerToSample points to an invalid object outside of the method.
Positives Beispiel:
FUNCTION_BLOCK FB_Sample_pos
VAR
END_VAR
METHOD PUBLIC nccl_TestMethod
VAR
stSample : ST_Sample;
pPointerToSample : POINTER TO ST_Sample; // COMPLIANT
END_VAR
--------------------------------------------------------------------
pPointerToSample := ADR(stSample);
Pointer/Referenzen jeden Zyklus neu setzen
Pointer und Referenzen sollten Sie jeden Zyklus neu setzen.
Durch einen Online-Change können sich die Adressen von statisch deklarierten Variablen und Objekten verändern. Daher sollten Pointer und Referenzen, die auf solche Variablen zeigen, jeden Zyklus neu gesetzt werden. Hierzu kann die Adresse der Variablen mittels ADR()-Operator neu abgefragt werden.
Pointer auf dynamisch erzeugte Objekte (__NEW) dürfen wiederum nicht jeden Zyklus neu gesetzt werden, sondern müssen so lange bestehen bleiben, bis das Objekt explizit freigegeben wird (__DELETE).
Werden Pointer/Referenzen am Eingang einer Methode verlangt, so bewirkt die zwingende Zuweisung aller Methoden-Eingangsparameter, dass die Pointer/Referenzen vom Aufrufer neu gesetzt werden.
Negatives Beispiel:
FUNCTION_BLOCK FB_Sample_neg
VAR
aBuffer : ARRAY[cMin..cMax] OF BYTE; // Sample buffer
pBuffer : POINTER TO BYTE := ADR(aBuffer); // Sample pointer to buffer
// NON COMPLIANT: the memory address of aBuffer could change during an online change. So pBuffer could become invalid.
END_VAR
Positives Beispiel:
FUNCTION_BLOCK FB_Sample_pos
VAR
aBuffer : ARRAY[cMin..cMax] OF BYTE; // Sample buffer
pBuffer : POINTER TO BYTE; // Sample pointer to buffer
END_VAR
-------------------------------------------------
pBuffer := ADR(aBuffer); // COMPLIANT: pointer is updated before usage in implementation
Pointer/Referenzen/Interfaces vor jeder Verwendung prüfen
Pointer, Referenzen und Interfaces sollten vor jeder Verwendung auf ihre Gültigkeit überprüft werden. Bei Pointern und Interfaces findet diese Überprüfung mit Hilfe der Abfrage auf „ungleich 0“ (<> 0) statt, bei Referenzen wird der Operator __ISVALIDREF() verwendet.
Für spezielle Überprüfungen eines Pointers steht für Ausnahmesituationen die Funktion F_CheckMemoryArea der Tc2_System-Bibliothek zur Verfügung, mit deren Hilfe der Speicherbereich abgefragt werden kann, auf den ein Pointer verweist.
Innerhalb der Bedingung, welche die Gültigkeit des Pointers prüft, sollte dieser nicht zugleich verwendet werden. Möchten Sie dies umsetzen, verwenden Sie zwingend den Operator AND_THEN. Siehe Beispiel 2.
Static Analysis:
Überprüfen mit Hilfe der folgenden Static Analysis Regeln:
- SA0039: Mögliche Null-Pointer-Dereferenzierung
- SA0046: Mögliche Verwendung nicht initialisierter Schnittstellen
- SA0145: Mögliche Verwendung nicht initialisierter Referenzen
Thematisch empfohlene Static Analysis Regeln:
Allgemeine Programmelemente für die folgenden Beispiele:
Funktionsbaustein FB_Sample implementiert das Interface I_Sample:
FUNCTION_BLOCK FB_Sample IMPLEMENTS I_Sample
Programm Sample:
PROGRAM Sample
VAR
pSample : POINTER TO FB_Sample;
refSample : REFERENCE TO FB_Sample;
ipSample : I_Sample;
END_VAR
Negatives Beispiel:
pSample^.DoSomething();
refSample.DoSomething();
ipSample.DoSomething();
Positives Beispiel 1:
IF pSample <> 0 THEN
pSample^.DoSomething();
END_IF
IF __ISVALIDREF(refSample) THEN
refSample.DoSomething();
END_IF
IF ipSample <> 0 THEN
ipSample.DoSomething();
END_IF
Positives Beispiel 2:
IF ipBuffer <> 0 THEN
IF ipBuffer.bAvailable THEN
ipBuffer.Clear();
END_IF
END_IF
IF ipBuffer <> 0 AND_THEN ipBuffer.bAvailable THEN
ipBuffer.Clear();
END_IF
Referenzen gegenüber Pointern vorziehen
Ziehen Sie Referenzen Pointern nach Möglichkeit vor, da Referenzen im Vergleich zu Pointern Typ-sicherer sind.
In speziellen Fällen ist jedoch die Verwendung von Pointern erforderlich, beispielsweise bei der Notwendigkeit von Pointer-Arithmetik. Ebenso werden gerne Puffer beliebiger Größe an eine Funktion übergeben. Hierzu werden ebenfalls Pointer verwendet.
Static Analysis:
Hilfreiche Regeln für eine möglicherweise erforderliche Pointer-Verwendung:
Siehe auch: