Attribute 'estimated-stack-usage'
The pragma transfers an estimated value for the stack size requirement.
Methods with recursive calls do not withstand a stack check because the stack usage cannot be determined. Consequently, a warning is issued for these methods. To suppress the warning, you can use the attribute to give the method an estimated value in bytes for the stack size requirement. The method then successfully passes the stack check.
Syntax: {attribute 'estimated-stack-usage' := '<estimated stack size in bytes>'}
Insertion location: First line above the declaration part of the method
Sample:
{attribute 'estimated-stack-usage' := '99'} // 99 bytes
METHOD SampleMethod : INT
VAR_INPUT
END_VAR
Warning issued:
The warning that is issued for recursive methods without the 'estimated-stack-usage' attribute is:
"C0298: Calculation of stack usage incomplete due to recursive calls, starting at '<FB.Method>'"
In a project that is unchanged compared to the last time the project was build, the warning is only issued when the Rebuild project command is used (not when the Build project command is used).
Setting the stack size:
The value of the maximum possible stack size can be configured in the real-time settings of the TwinCAT project (Settings tab > Global Task Config/Maximum Stack Size [KB]). The set maximum value is not completely available to the PLC project, but part of it is used by the TwinCAT runtime system, for example.
No stack calculation for stand-alone PLC projects Due to the decoupling from the System Manager, it is not possible to calculate the stack usage for a stand-alone PLC project. |
Recursive method call
Within the associated implementation, a method can call itself: either directly with the help of the THIS pointer or with the help of a local variable for the assigned function block.
Notice | |
Machine downtime due to possible stack overflow Unexpectedly deep recursions can lead to a stack overflow and thus to a machine downtime.
|
Sample: Calculation of the factorial
Within the function block FB_Factorial
, the factorial of a number is calculated in different ways. The various calculations are each carried out using a separate method.
- Method
Iterative
: Iterative - Method
Pragmaed
: Recursive with warning suppression - Method
Recursive
: Recursive
When the project is rebuilt, only the method Recursive
generates the warning C0298.
Structure ST_FactorialResult for saving the values:
// Contains the data of the factorial calculation of nNumber.
TYPE ST_FactorialResult :
STRUCT
nNumber : USINT;
nIterative : UDINT;
nRecursive : UDINT;
nPragmaed : UDINT;
END_STRUCT
END_TYPE
Function block FB_Factorial for calculating the factorial:
// Factorial calculation in different ways
FUNCTION_BLOCK FB_Factorial
VAR
nNumberIterative : UINT;
END_VAR
Property nNr including set function, for transferring the parameter for the iterative method:
{attribute 'monitoring' := 'variable'}
PROPERTY nNr : UINT
nNumberIterative := nNr;
Iterative calculation method:
// Iterative calculation
METHOD PUBLIC Iterative : UDINT
VAR
nCnt : UINT;
END_VAR
Iterative := 1;
IF nNumberIterative > 1 AND nNumberIterative <= 12 THEN
FOR nCnt := 1 TO nNumberIterative DO
Iterative := Iterative * nCnt;
END_FOR;
RETURN;
ELSE
RETURN;
END_IF
Recursive calculation method with attribute for suppressing warning C0298:
// Recursive calculation with suppressed warning
{attribute 'estimated-stack-usage' := '200'}
METHOD PUBLIC Pragmaed : UDINT
VAR_INPUT
nNumber : USINT;
END_VAR
Pragmaed := 1;
IF nNumber > 1 AND nNumber <= 12 THEN
Pragmaed := nNumber * THIS^.Pragmaed(nNumber := (nNumber - 1));
RETURN;
ELSE
RETURN;
END_IF
The pragma parameter for specifying the estimated stack size requirement is set to 200 bytes as an example. This is based on the following calculation:
Stack usage per method call:
Return value UDINT + input parameter USINT + method pointer = 4 bytes + 1 byte + 8 bytes = 13 bytes
Stack usage with a maximum of 12 calls:
12 * 13 bytes = 156 bytes, rounded up to 200 bytes
Recursive calculation method:
// Recursive calculation
METHOD PUBLIC Recursive : UDINT
VAR_INPUT
nNumber : USINT;
END_VAR
Recursive := 1;
IF nNumber > 1 AND nNumber <= 12 THEN
Recursive := nNumber * THIS^.Recursive(nNumber := (nNumber - 1) );
RETURN;
ELSE
RETURN;
END_IF
Main program MAIN:
PROGRAM MAIN
VAR
fbFactorial : FB_Factorial;
stFactorial : ST_FactorialResult := (nNumber := 9);
END_VAR
// Iterativ
fbFactorial.nNr := stFactorial.nNumber;
stFactorial.nIterative := fbFactorial.Iterative();
// Recursive
stFactorial.nRecursive := fbFactorial.Recursive(nNumber := stFactorial.nNumber);
// Pragmaed
stFactorial.nPragmaed := fbFactorial.Pragmaed(nNumber := stFactorial.nNumber);