Pointer, Referenzen, Interfaces

Themenpunkte:

  1. Temporäre Existenz von Pointern/Referenzen/Interfaces auf temporär existierende Objekte [++]
  2. Pointer/Referenzen jeden Zyklus neu setzen [++]
  3. Pointer/Referenzen/Interfaces vor jeder Verwendung prüfen [++]
  4. Referenzen gegenüber Pointern vorziehen [++]

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:

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: