Operator: __NEW
Der Operator ist eine Erweiterung der Norm IEC 61131-3.
Der __NEW-Operator reserviert dynamisch Speicher um Funktionsbausteine, benutzerdefinierte Datentypen oder Arrays von Standarddatentypen zu instanzieren. Der Operator gibt einen passend getypten Pointer zurück.
Voraussetzung: Im Eigenschaftendialog der übergeordneten Applikation, in der Registerkarte Optionen Applikationserzeugung, ist die Option Dynamische Speicherallozierung verwenden aktiviert.
Syntax
<pointer name> := __NEW( <type> ( , <size> )? ); __DELETE( <pointer name> ); <type> : <function block> | <data unit type> | <standard data type>
Der Operator erzeugt eine Instanz des Typs <type> und gibt einen Pointer auf diese Instanz zurück. Anschließend wird die Initialisierung der Instanz aufgerufen. Wenn es sich bei <type> um einen skalaren Standarddatentyp handelt, wird zusätzlich der optionale Operand <size> ausgewertet. Der Operator erzeugt dann ein Array des Typs <standard data type> der Größe <size>. Wenn der Versuch Speicher zu allozieren scheitert, gibt __NEW den Wert 0 zurück.
Verwenden Sie den Operator innerhalb der Zuweisung „:=„, ansonsten wird eine Fehlermeldung ausgegeben.
Ein Funktionsbaustein oder ein benutzerdefinierter Datentyp, dessen Instanz mit __NEW dynamisch erzeugt wird, belegt einen fixen Speicherbereich. Dafür ist es erforderlich, dass Sie die Objekte mit dem Pragma {attribute 'enable_dynamic_creation'} kennzeichnen. Das ist bei Funktionsbausteinen, die Teil einer Bibliothek sind, nicht erforderlich.
Tipp
Wenn Sie im Onlinebetrieb das Datenlayout des Funktionsbausteins ändern, können Sie anschließend kein Einloggen mit Online-Change ausführen. Der Speicherbereich der Funktionsbaustein-Instanz ist nämlich ungültig geworden. Eine Änderung des Datenlayouts nehmen Sie vor, wenn Sie beim Funktionsbaustein neue Variablen hinzufügen, bestehende Variablen löschen oder Datentypen von Variablen ändern.
Array (DWORD)
PROGRAM PLC_PRG
VAR
pdwScalar : POINTER TO DWORD; //Typed pointer
xInit : BOOL := TRUE;
xDelete : BOOL;
END_VAR
IF (xInit) THEN
pdwScalar := __NEW(DWORD, 16); // Allocates memory (16 dwords) and assigns them to pointer pdwScalar
END_IF
IF (xDelete) THEN
__DELETE(pdwScalar); // Frees memory of pointer
END_IFFunktionsbaustein
{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FBComputeGamma
VAR_INPUT
iAlpha : INT;
iBeta : INT;
END_VAR
VAR_OUTPUT
iGamma : INT;
END_VAR
VAR
END_VAR
iGamma := iAlpha + iBeta;
PROGRAM PLC_PRG
VAR
pComputeGamma : POINTER TO FBComputeGamma; // Typed pointer
xInit : BOOL := TRUE;
xDelete : BOOL;
iResult : INT;
END_VAR
IF (xInit) THEN
pComputeGamma := __NEW(FBComputeGamma); // Allocates memory
xInit := FALSE;
END_IF
pComputeGamma^.iAlpha := (pComputeGamma^.iAlpha + 1)MOD 100; // Sets first input of pComputeGamma
pComputeGamma^.iBeta := 10; // Sets second input of pComputeGamma
pComputeGamma^(); // Calls the FB pComputeGamma is pointing to
iResult := pComputeGamma^.iGamma; // Reads output of pComputeGamma
IF (xDelete) THEN
__DELETE(pComputeGamma); // Frees memory
END_IFBenutzerdefinierter Datentyp (DUT)
{attribute 'enable_dynamic_creation'}
TYPE ABCDATA :
STRUCT
iA, iB, iC, iD : INT;
END_STRUCT
END_TYPE
PROGRAM PLC_PRG
VAR
pABCData : POINTER TO ABCDATA; // Typed pointer
xInit : BOOL := TRUE;
xDelete : BOOL;
END_VAR
IF (xInit) THEN
pABCData := __NEW(ABCDATA); // Allocates memory
xInit := FALSE;
END_IF
IF (xDelete) THEN
__DELETE(pABCData); // Frees memory
END_IFArray (BYTE)
PROGRAM PLC_PRG
VAR
pbDataAlpha : POINTER TO BYTE;
pbDataBeta : POINTER TO BYTE;
xInit : BOOL := TRUE;
xDelete : BOOL;
usiCnt : USINT;
bTestC: BYTE;
END_VAR
IF (xInit) THEN
pbDataAlpha := __NEW(BYTE, 16); // Allocates 16 bytes for pbDataAlpha
pbDataBeta := __NEW(BYTE); // Allocates memory for pbDataBeta
xInit := FALSE;
FOR usiCnt := 0 TO 15 DO
pbDataAlpha[usiCnt] := usiCnt; // Writes to new array
END_FOR
pbDataBeta^:= 16#FF; // Writes to new data
END_IF
bTestC := pbDataAlpha[12]; // Reads new array by index access
IF (xDelete) THEN // Frees memory
__DELETE(pbDataAlpha);
__DELETE(pbDataBeta);
END_IFWichtig
Es ist nicht ratsam, zwei Tasks gleichzeitig auszuführen, die beide den __NEW-Operator aufrufen. Entweder Sie verwenden ein Semaphor (SysSemEnter) oder eine vergleichbare Technik, um einen konkurrierenden Aufruf von __NEW zu verhindern. Das bewirkt allerdings, dass bei umfangreicher Nutzung von __NEW ein höherer Jitter entsteht.
Empfehlenswert ist, nur in einer Task __NEW-Operatoren aufzurufen.