Typing of expressions
Neuron Power Engineer →types →expressions and →assignments according to the following rules:
-
The data type of the →variable to store the result of the →overloaded function influences the data type of the result of the function or operation. This rule does not correspond to the specifications within the →IEC-standard.
Examples VAR
int1, int2, int3 : INT := 32767;
dint1 : DINT := 32767;
ResultInt1 : INT;
ResultDint1, ResultDint2 : DINT;
END_VAR
ResultInt1 := int1 + int2; (* The addition is performed as an INT-operation. *)
ResultDint1 := int1 + int2; (* In contrast to the IEC-standard: 'int1' and 'int2' are converted to DINT. The addition is performed as an DINT-operation and assigned to 'ResultDint1'. *)
ResultDint2 := dint1 + int3; (* 'int3' is converted to DINT. The addition is performed as a DINT addition. *)
-
If the expressions do not include any concrete data type, typing is influenced by the data type of the variable to store the result of the overloaded function. This addon rule is an implementer-specific realization because the IEC-standard does not specify any on this.
Examples VAR
ResultDintA, ResultDintB, ResultDintC : DINT;
sint1 : SINT := 127;
END_VAR
ResultDintA := 127 + 127; (* The addition is performed as an DINT-operation because there is no other concrete data type. *)
ResultDintB := 127 + SINT#127; (* 'SINT#127' is converted to DINT. The addition is performed as an DINT-operation and assigned to 'ResultDintB'. *)
ResultDintC := 127 + sint1; (* 'sint1' is converted to DINT. The addition is performed as an DINT-operation and assigned to 'ResultDintC'.*)
-
In case of a →call that is using inputs, outputs and/or a return value with the same →generic data type, Neuron Power Engineer types all of these inputs, outputs and the return value of the call – even if only one of these elements is connected to a concrete data type.
Examples VAR
Var1, OUT1 : INT;
iForceMrk1 : FORCEMRK;
END_VAR
Var1 := ADD(IN1 := 1, IN2 := 3);
(* The inputs and the return value of 'ADD' are using the same generic data type. As the INT variable 'Var1' is assigned to the call of 'ADD' (in particular to the return value of 'ADD'), the call is typed with 'INT'. Subsequently, the inputs of 'ADD' are typed with 'INT' as well. *)
iForceMrk1(IN := 3, OUT => OUT1);
(* The input and the output of 'FORCEMRK' are using the same generic data type. As output 'OUT' of 'iForceMrk1' is assigned to the INT variable 'OUT1', the call is typed with 'INT'. Subsequently, the input of 'iForceMrk1' is typed with 'INT' as well. *)
If a →user-defined data type is used for typing, Neuron Power Engineer uses the →base type. This rule is of importance, if an →Initial value is defined within the user-defined data type – in this case the initial value of the data type is not used but the initial value of the base type.
Compare: In case of an →array data type (incl. anARRAY
declaration of a variable) or a →structured data type, the user-defined data type is the base type.Examples TYPE
MyInt : INT := 6;
MyStruct : Struct
Elem1 : MyInt;
END_STRUCT;
MyArray : Array [1..1] OF MyInt := [99];
END_TYPE
FUNCTION_BLOCK myFB
VAR
outDerived : MyInt;
outArray1 : MyArray;
outArray2 : Array [1..1] OF MyInt;
outStruct : MyStruct;
iForceMrk1, iForceMrk2, iForceMrk3, iForceMrk4 : FORCEMRK;
END_VAR
iForceMrk1(OUT => outDerived);
(* 'OUT' gets value '0' because initial value '0' of 'INT' is used. Here the base type is 'INT'. *)
(* The initial value '6' of 'MyInt' is NOT used. *)
iForceMrk2(OUT => outArray1);
iForceMrk3(OUT => outArray2);
iForceMrk4(OUT => outStruct);
(* Each element of output 'OUT' gets value '6' because initial value '6' of 'MyINT' is used. *)
(* Here the base type of each element is 'MyInt* while the base type of 'OUT' is 'ARRAY [...] OF' or 'STRUCT'. *)
END_FUNCTION_BLOCK
-
In 2 or more calls are connected with each other and their connected inputs, outputs and/or the connected return value are of a generic data type (but the others are of a concrete data type), Neuron Power Engineer types all of these inputs, outputs and the return value of the call by using the lowest common data type.
Example: The return value of thePACK
block is of the generic data typeANY_ELEMENTARY
and the inputs are of the concrete data typeBYTE
, the input of theTO_DINT
block is also of the generic data typeANY_ELEMENTARY
and the return value is of the concrete data typeDINT
. In case of the following code, the return value ofPACK
and the input ofTO_DINT
are typed withBOOL
(BOOL
is the lowest common data type ofANY_ALEMENTARY
).Example VAR
Var1 : DINT;
ByteVar1 : BYTE:= 16#AB;
END_VAR
Var1 := TO_DINT(PACK(ByteVar1, ByteVar1)); (* 'Var1' evaluates to value '1'. This is not a value expected from 'PACK', but the correct result due to the typing. *)
Do not nest the calls in order to avoid the typing using to the lowest common data type.
Workaround 1: Declare an auxiliary variable. Assign one call to this auxiliary variable. Assign this auxiliary variable as parameter for the other call.Example for workaround 1
VAR
Var1 : DINT;
ByteVar1 : BYTE := 16#AB;
HelperVar : DINT; (* the auxiliary variable *)
END_VAR
HelperVar := PACK(ByteVar1, ByteVar1);
Var1 := TO_DINT(HelperVar); (* 'Var1' evaluates to value '43947'. This a value as expected from 'PACK' *)
Workaround 2: Create a user-defined POU (e.g. a function). Assign one call of the blocks (in the following example:
PACK
) to the result value of the function. Call the function as parameter of the other block (then:DINT
).Example for workaround 2 FUNCTION myFun1 : DWORD
VAR
ByteVar1 : BYTE:= 16#AB;
END_VAR
myFun1 := PACK(ByteVar1, ByteVar1); (* 'PACK' is assigned to the return value of function 'myFun1'. *)
END_FUNCTION
FUNCTION_BLOCK myFB2
VAR
Var1 : DINT;
END_VAR
Var1 := TO_DINT(IN:=myFun1()); (* 'Var1' evaluates to value '43947'. This a value as expected from 'PACK'. *)
END_FUNCTION_BLOCK