Dynamic memory
Topics:
PLC_Library Tc3_DynamicMemory The use of dynamic memory can be simplified with the help of the PLC library Tc3_DynamicMemory. |
Perform dynamic memory allocations carefully
Dynamic memory allocations using __NEW() should be done with care. The reason is that they change the memory requirement and array limits at runtime, for example. These changes should always be taken into account, in order to prevent unauthorized memory access resulting in a program crash.
With dynamic memory allocation it is particularly important to observe which memory is allocated and how often. Since dynamic memory allocations may affect the runtime and perhaps the memory, they should only be carried out once and at certain times, such as during startup or after a system retrofit.
Also note that dynamically allocated memory must subsequently be released again using __DELETE().
Negative sample:
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
Method 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
Positive sample:
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
Method 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 method 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