Schleifen und Bedingungen
Themenpunkte:
CASE-Anweisung nur mit Enumerationsinstanz
In einer CASE-Anweisung sollten Sie statt „magischer“ Zahlen eine Enumerationsinstanz samt den dazugehörigen Enumeratoren zur Definition der Zustandsmaschine verwenden. Dadurch sind die Werte der Zustandsmaschine selbstsprechend und es werden keine „Magic Numbers“ verwendet.
Beachten Sie auch die folgenden Themenpunkte der Programmierkonventionen:
- Attribute 'qualified_only' und 'strict' bei Enumeration verwenden
 - Keine „magischen Werte/magic numbers“
 
Negatives Beispiel:
PROGRAM Sample_neg
VAR 
    nState  : INT; // Used to operate the sample state machine
END_VAR // NON COMPLIANT: Integer variable and "magic values" are used to define state machine
CASE nState OF 
    0: F_DoSomethingUsefulHere(); 
    1: F_DoSomethingUsefulHere(); 
    2: F_DoSomethingUsefulHere(); 
ELSE 
    F_DoSomethingUsefulHere(); 
END_CASEPositives Beispiel:
// Enumeration for the positive sample 
{attribute 'qualified_only'}
{attribute 'strict'}
TYPE E_SampleState : 
( 
    Entry,  // Entrance part of a state 
    Work,   // Action part of a state 
    Finish  // Exit part of a state 
);
END_TYPEPROGRAM Sample_pos 
VAR 
    eState  : E_SampleState;  // Used to operate the sample state machine
END_VAR// COMPLIANT: Enum instance and enum values are used to define state machine 
CASE eState OF 
    E_SampleState.Entry: 
        F_DoSomethingUsefulHere(); 
    E_SampleState.Work: 
        F_DoSomethingUsefulHere();   
    E_SampleState.Finish: 
        F_DoSomethingUsefulHere(); 
END_CASEGrenzen einer Schleife als Konstante deklarieren
Als Grenzen einer Schleife sollten konstante Variablen verwendet werden. Wenn innerhalb der Schleife auf ein Array zugegriffen wird, sollte das Array über die gleichen konstanten Variablen deklariert sein.
- Untergrenze des Arrays = Untergrenze der Schleife = konstante Variable 1
 - Obergrenze des Arrays = Obergrenze der Schleife = konstante Variable 2
 
Beachten Sie auch die folgenden Empfehlungen:
Static Analysis:
Thematisch empfohlene Static Analysis Regeln:
- SA0072: Ungültige Verwendung einer Zählervariablen
 - SA0080: Schleifenindexvariable für Arrayindex überschreitet Array-Bereich
 - SA0081: Obergrenze ist kein konstanter Wert
 
Allgemeine Programmelemente für die folgenden Beispiele:
TYPE ST_Object :
STRUCT
    sName        : STRING;
    nID          : UINT;
END_STRUCT
END_TYPEPROGRAM Sample
VAR CONSTANT
    cMin         : UINT := 1;
    cMax         : UINT := 10;
END_VAR
VAR
    aObjects     : ARRAY[cMin..cMax] OF ST_Object;
    bInitDone    : BOOL;
    nForIdx      : UINT;
END_VARNegatives Beispiel:
VAR
    nUpperBorder : UINT;
END_VAR// Initialize objects
IF NOT bInitDone THEN
    nUpperBorder := cMin;
    FOR nForIdx := nUpperBorder TO 10 BY 1 DO
        aObjects[nForIdx].sName := CONCAT('Object_', UDINT_TO_STRING(nForIdx));
        aObjects[nForIdx].nID   := nForIdx;
    END_FOR
 
    bInitDone := TRUE;
END_IFPositives Beispiel:
// Initialize objects
IF NOT bInitDone THEN
    FOR nForIdx := cMin TO cMax BY 1 DO
        aObjects[nForIdx].sName := CONCAT('Object_', UDINT_TO_STRING(nForIdx));
        aObjects[nForIdx].nID   := nForIdx;
    END_FOR
 
    bInitDone := TRUE;
END_IFIn CASE-Anweisung alle Enumerationswerte der Enumerationsvariablen behandeln
In einer CASE-Anweisung sollten Sie alle Enumerationswerte der Enumerationsvariablen behandeln. Falls dies bei einer großen Anzahl von gleichen oder ungenutzten Enumerationswerten nicht sinnvoll sein sollte, kann für diese Fälle ein ELSE-Zweig verwendet werden.
Static Analysis:
Überprüfen mit Hilfe der folgenden Static Analysis Regeln:
Allgemeine Programmelemente für die folgenden Beispiele:
// Enumeration for all samples in this rule 
{attribute 'qualified_only'}
{attribute 'strict'}
TYPE E_ColorTrafficLight : 
( 
    Red      := 0, 
    Yellow, 
    Green 
); 
END_TYPEPROGRAM Sample 
VAR 
    eColorTrafficLight : E_ColorTrafficLight; // Used to handle the state of the traffic light
END_VARNegatives Beispiel:
CASE eColorTrafficLight OF      // NON COMPLIANT: enum value Green is not handled 
    E_ColorTrafficLight.Red: 
        SetLightRed(); 
    E_ColorTrafficLight.Yellow:    
        SetLightYellow();
END_CASEPositives Beispiel:
CASE eColorTrafficLight OF      // COMPLIANT: all enum values are handled 
    E_ColorTrafficLight.Red: 
        SetLightRed(); 
    E_ColorTrafficLight.Yellow: 
        SetLightYellow(); 
    E_ColorTrafficLight.Green: 
        SetLightGreen(); 
END_CASEIF-ELSIF-Anweisungen mit ELSE-Zweig
Aus Sicherheitsgründen wird empfohlen, einem IF-Konstrukt ein ELSE hinzuzufügen, falls es über ein ELSIF verfügen sollte. Ein ELSIF hat empfohlener Weise ein ELSE zur Folge, um zu verdeutlichen, dass alle möglichen Fälle bedacht worden sind. Falls für den ELSE-Zweig keine Anweisungen geplant sind, sollte nach dem ELSE ein Semikolon folgen. Per Kommentar können Sie für die Abnahme/Inbetriebnahme des Programms erläutern, dass der ELSE-Fall bedacht wurde und warum er über keine Anweisungen verfügt.
Allgemeine Programmelemente für die folgenden Beispiele:
PROGRAM Sample
VAR
    nTest   : INT:= 10;        // Test value for sample
END_VARNegatives Beispiel:
IF nTest < 10 THEN             // NON COMPLIANT: the ELSE should be used in any way
    nTest := 20;
ELSIF nTest > 20 THEN
    nTest := 10;
END_IFPositives Beispiel 1:
IF nTest < 10 THEN             // COMPLIANT with any action in ELSE
    nTest := 20;   
ELSIF nTest > 20 THEN
    nTest := 10;
ELSE
    F_DoSomethingUsefulHere(); // it's just a sample
END_IFPositives Beispiel 2:
IF nTest < 10 THEN             // COMPLIANT with a comment in ELSE
    nTest := 20;   
ELSIF nTest > 20 THEN
    nTest := 10;
ELSE
    ;(* No action needed for the case that nTest is >= 10 and <= 20 *)
END_IFReihenfolge der IF-Bedingungen
Die Reihenfolge der IF-/ELSIF-/ELSE-Bedingungen entsprechend der Eintrittswahrscheinlichkeit anordnen. So sollte der am wahrscheinlichsten eintretende Fall zuerst abgehandelt werden. Dies verbessert sowohl die Lesbarkeit als auch in einigen Fällen die Performanz, weil nichtzutreffende Abfragen seltener durchlaufen werden.
Positives Beispiel:
IF SUCCEEDED(hrErrorCode) THEN
    IF nReqIdx < cIdxMax THEN    // requested index in range
        ; // handle request
    ELSIF nReqIdx = cIdxMax THEN // requested index in range but at upper limit
        ; // handle request
    ELSE
        ; // add error output (error caused by invalid index)
    END_IF
ELSE
    ;     // add error handling (error in previous step)
END_IF