Conditional pragmas
Conditional pragmas are used to influence the code generation in the precompile process or the compile process. The programming language ST supports these pragmas.
From TC 3.1 build 4024 you can use the conditional pragmas both in the declaration part and in the implementation part. Only the operators "defined (<identifier>)" and "hasvalue (<identifier>, '<value>')" for simple compiler definitions are supported in the declaration part. The special uses of the two operators listed below are excluded from this. In addition, it is not possible to define the components of an enumeration or the data type of an alias with the help of conditional pragmas. Conditional pragmas are supported in the PLC project, but not in libraries. In previous TC 3.1 versions the pragmas used in the declaration part were not evaluated. |
With conditional pragmas you influence whether declaration or implementation code is taken into account for the compilation. You can make this dependent, for example, on whether a certain compiler definition is defined or has a certain value, whether a certain variable is declared, whether a certain function block exists, etc.
Pragma | Description |
---|---|
Definition in the code:
Examples:
Definition in the PLC project properties:
Examples:
| The definition can be queried later with the defined operator. In addition, the optionally specified value can be queried and compared later with the hasvalue operator. |
{undefine <identifier>} | The {define} instruction of the <identifier> is canceled, and the identifier is then "undefined" again. If the specified identifier is currently not defined, the pragma is ignored. |
{IF <expr>}... {ELSIF <expr>}... {ELSE}... END_IF} | These are pragmas for conditional compilation. The specified expressions <expr> must be constant during the compilation; they are evaluated in the order in which they appear here, until one of the expressions shows a non-zero value. The text linked to the instruction is compiled; the other lines are ignored. The order of the sections is set. The ELSIF and ELSE sections are optional. The ELSIF sections may be used any number of times. Within the constant <expr> you can use multiple conditional compile operators. |
<expr>} | You can use one or several operators within the constant expression <expr> in a conditional compile pragma {IF} or {ELSIF}. |
Different scopes
You can enter global define definitions as compiler definitions in the PLC project properties (Compile category) or at System Manager level one node above (Compiler Defines grouping, see documentation on variant management). The compiler definitions defined here are valid in the entire PLC project. Also, you can specify several define-definitions separated by commas in the PLC project properties.
Furthermore, you can define local compiler definitions in the declaration and implementation part of the PLC elements. These are then valid in the respective declaration or implementation editor.
See also:
- Structured Text (ST), Extended Structured Text (ExST)
- Variant management
Operator defined (<identifier>)
The operator causes the expression to be assigned the value TRUE. A prerequisite is that the <identifier> was defined using a {define} instruction and was subsequently not undefined with an {undefine} instruction, in which case FALSE is returned.
Sample 1:
Requirement: There are two PLC projects, Plc1 and Plc2. Variable pdef1 is defined by a {define} instruction in Plc1, but not in Plc2.
{IF defined (pdef1)}
(* This code is processed in Plc1 *)
{info 'pdef1 defined'}
hugo := hugo + SINT#1;
{ELSE}
(* the following code is only processed in Plc2 *)
{info 'pdef1 not defined'}
hugo := hugo - SINT#1;
{END_IF}
In addition, a sample for a message pragma is included: Only the information pdef1 defined is shown in the message window when the PLC project is compiled, since pdef1 is actually defined. The message 'pdef1 not defined' is issued, if pdef1 is not defined.
Sample 2:
In the following sample, the variable sVariantUsed is initialized with different values depending on the valid compiler-define. In addition, either an allocated input variable or an output variable is declared. The variable nCounter is declared in any case, i.e. independent of the valid compiler definitions.
{IF defined (Variant1)}
sVariantUsed : STRING := 'Variant1';
bOutput AT%Q* : BOOL;
{ELSE}
sVariantUsed : STRING := 'NotVariant1';
bInput AT%I* : BOOL;
{END_IF}
nCounter : INT;
Operators for the implementation part
The operators presented in the following can only be used in the implementation part and are not evaluated in the declaration part.
Operator defined (variable: <variable>)
This operator causes the expression to be assigned the value TRUE, if the variable <variable> is declared within the current scope; otherwise FALSE is returned.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. Variable g_bTest is declared in Plc1, but not in Plc2.
{IF defined (variable: g_bTest)}
(* the following code is only processed in Plc2*)
g_bTest := x > 300;
{END_IF}
Operator defined (type: <identifier>)
This operator causes the expression to be assigned the value TRUE, if a data type with the identifier <identifier> is declared; otherwise FALSE is returned.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. Data type DUT is declared in Plc1, but not in Plc2.
{IF defined (type: DUT)}
(* the following code is only processed in Plc1*)
bDutDefined := TRUE;
{END_IF}
Operator defined (pou: <pou name>)
This operator causes the expression to be assigned the value TRUE, if a function block with the name <pou name> is defined; otherwise FALSE is returned.
With the help of the syntax "pou: <pou name>.<method name>", you can also check whether the function block mentioned possesses methods or actions with the names mentioned.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. CheckBounds function block exists in Plc1, but not in Plc2.
{IF defined (pou: CheckBounds)}
(* the following code is only processed in Plc1 *)
arrTest[CheckBounds(0,i,10)] := arrTest[CheckBounds(0,i,10)] + 1;
{ELSE}
(* the following code is only processed in Plc2 *)
arrTest[i] := arrTest[i]+1;
{END_IF}
Operator defined (IsLittleEndian)
The operator causes the expression to be set to FALSE, if the CPU is "BigEndian (Motorola Byte Order)".
Operator defined (IsFPUSupported)
If the expression returns TRUE, the code generator FPU (floating-point unit) generates code for calculations with REAL values. Otherwise TwinCAT emulates FPU operations, which is, however, significantly slower.
Operator hasvalue (RegisterSize, '<register size>')
<register size>: Size of a CPU register in bits
The operator causes the expression to return TRUE if the size of a CPU register equals <register size>.
Possible values for <register size>
- 16 for C16x,
- 64 for X86 64-bit
- 32 for X86
Operator hasvalue (PackMode, '<pack mode value>')
The checked PackMode depends on the device description, not on the pragma, which can be specified for individual DUTs.
Operator hasattribute (pou: <pou name>, '<attribute>')
Operator causes the expression to be assigned the value TRUE, if the attribute <attribute> is specified in the first line of the declaration part of the function block pou-name; otherwise FALSE is returned.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. A function fun1 is defined in Plc1 and Plc2, but the attribute vision is also assigned to it in Plc1.
In Plc1:
{attribute 'vision'}
FUNCTION fun1 : INT
VAR_INPUT
i : INT;
END_VAR
VAR
END_VAR
In Plc2:
FUNCTION fun1 : INT
VAR_INPUT
i : INT;
END_VAR
VAR
END_VAR
Pragma instruction:
{IF hasattribute (pou: fun1, 'vision')}
(* the following code is only processed in Plc1 *)
ergvar := fun1(ivar);
{END_IF}
See also:
Operator hasattribute (variable: <variable>, '<attribute>')
Operator causes the expression to be assigned the value TRUE, if the variable is assigned the attribute '<attribute>' with the instruction {attribute '<attribute>'} in the line before the variable declaration; otherwise FALSE is returned.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. The variable g_globalInt is used in Plc1 and Plc2, but the attribute 'DoCount' is also assigned to it in Plc1.
Declaration g_GlobalInt in Plc1
VAR_GLOBAL
{attribute 'DoCount'}
g_globalInt : INT;
g_multiType : STRING;
END_VAR
Declaration g_GlobalInt in Plc2
VAR_GLOBAL
g_globalInt : INT;
g_multiType : STRING;
END_VAR
Pragma instruction:
{IF hasattribute (variable: g_globalInt, 'DoCount')}
(* the following code is only processed in Plc1 *)
g_globalInt := g_globalInt + 1;
{END_IF}
See also:
Operator hastype (variable: <variable>, <type-spec>)
The operator causes the expression to return the value TRUE, if the variable <variable> is of data type <type-spec>; otherwise FALSE is returned.
Possible data types for <type-spec>:
BOOL | BYTE | DATE | DATE_AND_TIME | DINT | DWORD | INT | LDATE | LDATE_AND_TIME | LINT | LREAL | LTIME | LTIME_OF_DAY | LWORD | REAL | SINT | STRING | TIME | TIME_OF_DAY | ULINT | UDINT | UINT | USINT | WORD | WSTRING
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. The variable g_multitype is declared in Plc1 with the data type LREAL, but in Plc2 with the data type STRING.
{IF (hastype (variable: g_multitype, LREAL))}
(* the following code is only processed in Plc1 *)
g_multitype := (0.9 + g_multitype) * 1.1;
{ELSIF (hastype (variable: g_multitype, STRING))}
(* the following code is only processed in Plc2 *)
g_multitype := 'this is a multitalent';
{END_IF}
Operator hasvalue (<define-ident>, '<char-string>')
The operator causes the expression to return the value TRUE, if a variable with identifier <define-ident> is defined and has the value <char-string>; otherwise FALSE is returned.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. The variable test is used in the PLC projects Plc1 and Plc2; in Plc1 it is given the value 1, in Plc2 the value 2.
The compiler definition can either be set in the PLC project properties via test := '1'
or in the implementation part of the POU via {define test '1'}
.
{IF hasvalue(test,'1')}
(* the following code is only processed in Plc1 *)
x := x + 1;
{ELSIF hasvalue(test,'2')}
(* the following code is only processed in Plc2 *)
x := x + 2;
{END_IF}
Operator NOT <operator>
The expression is assigned the value TRUE, if the inverse of <operator> returns the value TRUE. <operator> can be one of the operators described in this chapter.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. PLC_PRG1 exists in Plc1 and Plc2; POU CheckBounds exists only in Plc1.
{IF defined (pou: PLC_PRG1) AND NOT (defined (pou: CheckBounds))}
(* the following code is only processed in Plc2 *)
bANDNotTest := TRUE;
{END_IF}
Operator <operator> AND <operator>
The expression is assigned the value TRUE if the two specified operators return TRUE. <operator> can be one of the operators described in this chapter.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. PLC_PRG1 exists in Plc1 and Plc2; the POU CheckBounds exists only in Plc1.
{IF defined (pou: PLC_PRG1) AND (defined (pou: CheckBounds))}
(* the following code is only processed in Plc1, *)
bANDTest := TRUE;
{END_IF}
Operator <operator> OR <operator>
The expression returns TRUE, if one of the two operators returns TRUE. <operator> can be one of the operators described here.
Sample:
Requirement: There are two PLC projects, Plc1 and Plc2. PLC_PRG1 exists in Plc1 and Plc2; the POU CheckBounds exists only in Plc1.
{IF defined (pou: PLC_PRG1) OR (defined (pou: CheckBounds))}
(* the following code is only processed in Plc1 and in Plc2 *)
bORTest := TRUE;
{END_IF}