Dynamischer Speicher

Themenpunkte:

  1. Dynamische Speicherallokationen mit Bedacht durchführen [++]
Dynamischer Speicher 1:

SPS_Bibliothek Tc3_DynamicMemory

Die Verwendung von dynamischem Speicher kann mit Hilfe der SPS-Bibliothek Tc3_DynamicMemory vereinfacht werden.

Dynamische Speicherallokationen mit Bedacht durchführen

Dynamische Speicherallokationen mittels __NEW() sollten Sie mit Bedacht durchführen. Grund hierfür ist, dass diese den Speicherbedarf und beispielsweise Array-Grenzen zur Laufzeit verändern. Diese Änderungen sollten Sie stets berücksichtigen, um unerlaubte Speicherzugriffe und damit einen Programmabsturz zu verhindern.

Achten Sie bei dynamischen Speicherallokationen insbesondere darauf, welcher Speicher allokiert wird und wie oft dies geschieht. Da dynamische Speicherallokationen die Laufzeit und ggf. den Speicher beeinträchtigen können, sollten sie nur einmalig zu bestimmten Zeitpunkten durchgeführt werden, wie z. B. beim Hochfahren oder nach dem Umrüsten einer Anlage.

Beachten Sie außerdem, dass dynamisch allokierter Speicher mittels __DELETE() wieder freigegeben werden muss.

Negatives Beispiel:

FUNCTION_BLOCK FB_Sample_neg
VAR
    pDynamicLRealArray : POINTER TO LREAL;  // Pointer to dynamic array
    nArrayCounter      : INT;               // Counter variable
    bInit              : BOOL;              // Initialize array only once
END_VAR
(* NON COMPLIANT:
1: If the amount of new LREALs is constant (in this case 10 elements), use a static ARRAY [0..10] OF LREAL.
2: If the amount of new LREALs is dynamic, do not use magic numbers. If the amount of elements (10) is changed here, there would be no way to ensure that this number is also changed in any other code parts.
3: If an array is created dynamically and assigned to a pointer, do not use this original pointer to work on the array. The start address of the array would be overwritten. *)
IF NOT bInit THEN
    pDynamicLRealArray := __NEW(LREAL, 10);                   // NON COMPLIANT: see above (1, 2)
    FillDynamicArray();
    bInit              := TRUE; 
END_IF

Methode FillDynamicArray:

FOR nArrayCounter := 1 TO 10 DO                                // NON COMPLIANT: see above (2)
    pDynamicLRealArray^ := 1.25;
    pDynamicLRealArray  := pDynamicLRealArray + SIZEOF(LREAL); // NON COMPLIANT: see above (3)
END_FOR

Positives Beispiel:

FUNCTION_BLOCK FB_Sample_pos
VAR
    pDynamicLRealArray  : POINTER TO LREAL; // Pointer to dynamic array
    nDynamicArrayLen    : INT;              // Dynamic array length
    nArrayCounter       : INT;              // Counter variable
    pDynamicLRealTemp   : POINTER TO LREAL; // Temp. pointer to dynamic array
    bInit               : BOOL;             // Initialize array only once
END_VAR
IF NOT bInit THEN
    nDynamicArrayLen    := F_CalculateBufferLen();   
    pDynamicLRealArray  := __NEW(LREAL, nDynamicArrayLen);     // COMPLIANT
    FillDynamicArray();
    bInit               := TRUE;
END_IF

Methode FillDynamicArray:

// Do not work on the array with the pointer that points to the start address of the dynamic array. Use a temporary pointer for working on the array to keep the start address of the array.
pDynamicLRealTemp := pDynamicLRealArray;

// The following FOR-statement is COMPLIANT if nDynamicArrayLen is the length of array in any case.
FOR nArrayCounter := 1 TO nDynamicArrayLen DO 
    pDynamicLRealTemp^ := 1.25;
    pDynamicLRealTemp  := pDynamicLRealTemp + SIZEOF(LREAL);   // COMPLIANT: Temporary pointer used to work on the array
END_FOR

Alternative Methode FillDynamicArray:

// The following FOR-statement is COMPLIANT if nDynamicArrayLen is the length of array in any case.
FOR nArrayCounter := 1 TO nDynamicArrayLen DO 
    pDynamicLRealArray[nArrayCounter-1] := 1.25;               // COMPLIANT: Pointer is not changed
END_FOR