Dynamischer Speicher
Themenpunkte:
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