Allokierte Variablen

Themenpunkte:

  1. Keine direkte Adressierung verwenden [++]
  2. Mehrfache Schreibzugriffe auf Ausgänge vermeiden [++]
  3. Überlappende Speicherbereiche von Adressvariablen vermeiden [+]

Keine direkte Adressierung verwenden

Für allokierte Variablen sollte keine direkte Adressierung verwendet werden. Statt einer direkten Adressierung wird die Verwendung der automatischen Adressierung mit Hilfe des Platzhalters * empfohlen. Mit dem Platzhalter * (%I*, %Q* bzw. %M*) wird eine flexible und optimierte Adressierung von TwinCAT automatisch durchgeführt.

Im Implementierungsteil sollten ebenfalls keine direkten Adresszugriffe stattfinden.

Static Analysis:

Überprüfen mit Hilfe von folgenden Static Analysis Regeln:

Thematisch empfohlene Static Analysis Regel:

Negatives Beispiel:

VAR
    bInputSignal  AT%IX4.0 : BOOL;
    bVar                   : BOOL;
END_VAR
bVar := %IX0.0;

Positives Beispiel:

VAR
    bInputSignal  AT%I*    : BOOL;
END_VAR

Mehrfache Schreibzugriffe auf Ausgänge vermeiden

Mehrfache Schreibzugriffe auf Ausgänge sollten vermieden werden. Ein mehrfacher Schreibzugriff auf Ausgänge tritt auf, wenn Ausgänge an mehr als einer Stelle im Programm geschrieben werden.

Ausnahme dieser Regel ist, wenn die Zuweisungen in verschiedenen Zweigen einer IF- bzw. CASE-Anweisung durchgeführt werden.

Static Analysis:

Überprüfen mit Hilfe von Static Analysis Regel:

Die Regel SA0004 ist auch in der lizenzfreien Variante Static Analysis Light enthalten.

Negatives Beispiel:

PROGRAM Sample_neg
VAR
    bErrorLed      AT%Q*  : BOOL;             // Machine's error LED
    bErrorDrill           : BOOL;             // Drill error status
    bErrorTransport       : BOOL;             // Transport error status
    nTestCounter          : WORD;             // Simple counter
END_VAR
--------------------------------------------------------------------
bErrorLed := bErrorDrill OR bErrorTransport;  // NON COMPLIANT: bErrorLed will be written more than once: See action CounterInc
CounterInc();
--------------------------------------------------------------------
--------------------------------------------------------------------
(* --- Method: CounterInc ---
   This method increments the counter and checks if nCounterValue is equal to 0 *)
bErrorLed   := (nTestCounter = 0);            // NON COMPLIANT: bErrorLed will be written more than once: See program MAIN
nTestCounter := nTestCounter + 1; 

Positives Beispiel:

PROGRAM Sample_pos
VAR
    bErrorLed      AT%Q* : BOOL;     // Machine's error LED
    bErrorDrill          : BOOL;     // Drill error status
    bErrorTransport      : BOOL;     // Transport error status
    bErrorCounter        : BOOL;     // Test counter error status
    nTestCounter         : WORD;     // Simple counter
END_VAR
--------------------------------------------------------------------
CounterInc();
    bErrorLed := bErrorDrill         // COMPLIANT
    OR bErrorTransport  
    OR bErrorCounter;
--------------------------------------------------------------------
--------------------------------------------------------------------
(* --- Method: CounterInc ---
This method increments the counter and checks if nCounterValue is equal to 0 *)
bErrorCounter  := (nTestCounter = 0); // COMPLIANT
nTestCounter   := nTestCounter + 1;

Überlappende Speicherbereiche von Adressvariablen vermeiden

Überlappende Speicherbereiche von Adressvariablen sollten vermieden werden. Überlappende Speicherbereiche treten auf, wenn derselbe Speicherplatz von mehreren Variablen belegt wird.

Wenn ein überlappender Speicherbereich programmtechnisch benötigt wird, können hierfür UNIONs als gezieltes Stilmittel genutzt werden. Überlappende Speicherbereiche von anderen Variablen, z. B. von Adressvariablen, sollten hingegen vermieden werden.

Static Analysis:

Überprüfen mit Hilfe von Static Analysis Regel:

Die Regel SA0028 ist auch in der lizenzfreien Variante Static Analysis Light enthalten.

Negatives Beispiel:

PROGRAM Sample_neg
VAR
    nTestWord       AT%MW2  : WORD;  // Test WORD
    nTestLowByte    AT%MB4  : BYTE;  // NON COMPLIANT: overlaps with nTestWord
    nTestHighByte   AT%MB5  : BYTE;  // NON COMPLIANT: overlaps with nTestWord
END_VAR
--------------------------------------------------------------------
nTestLowByte   := 0;                 // NON COMPLIANT: writes nTestWord = 16#xx00
nTestHighByte  := 0;                 // NON COMPLIANT: writes nTestWord = 16#00xx
nTestWord      := 16#C0FF;           // Writes nTestLowByte and nTestHighByte too

Positives Beispiel:

// Structure for the positive sample
TYPE ST_2_BYTES :
STRUCT
    nLow        : BYTE;        // Low byte
    nHigh       : BYTE;        // High byte
END_STRUCT
END_TYPE
// Union for the positive sample
TYPE U_BYTE_WORD :
UNION
    stLowHigh   : ST_2_BYTES;  // Struct with two bytes
    nValue      : WORD;        // Test WORD to be united with the two-byte-struct
END_UNION
END_TYPE
PROGRAM Sample_pos
VAR
    uTestWordToBytes   AT%MW2  : U_BYTE_WORD;                // Test union
    nTestLowByte               : BYTE;                       // COMPLIANT: not addressed
    nTestHighByte              : BYTE;                       // COMPLIANT: not addressed
END_VAR
--------------------------------------------------------------------
uTestWordToBytes.nValue := 16#C0FF;                          // A test value 
nTestLowByte            := uTestWordToBytes.stLowHigh.nLow;  // Will be 16#FF
nTestHighByte           := uTestWordToBytes.stLowHigh.nHigh; // Will be 16#C0

 

Siehe auch: