In Automation Studio, there are several ways to pass pointers (or pointer-like references) to functions and function blocks. Below, I’ve compiled three common approaches, outlining their advantages and potential pitfalls.
1. Use an Input-Output Variable
- Compile-Time Type Checking
Because the type is checked at compile time, you do not need to worry about passing the wrong type. - No Null Pointer Check Required
Since Automation Studio enforces that the variable is always provided, there is no need for a runtime null pointer check. - Best Use Case
This approach is well-suited for mandatory data that your function or function block must always receive.
2. Use an Input Variable with the “Reference” Option
When you declare a function or function block input with the “Reference” option:
- No Compile-Time Type Checking
As you need to pass the Variables address with the ADR()-operator, you will not have any type checks at compile time. - Optional Data
If you do not pass an actual variable, you must be careful not to access this reference inside your function or function block - Otherwise you would send the PLC to Service-Mode ungracefully. - Checking for Null Pointer
Since the reference is implicitly dereferenced, you must useADR()
to check whether a valid address was provided. This can feel counterintuitive if you’re used to C/C++ pointer checks.
IF ADR(RefInStruct) <> 0 THEN
RefInStruct.Value := RefInStruct.Value + 1;
END_IF
- No Short-Circuit Evaluation
In IEC 61131-3, all operands of a logical expression are evaluated, even if the result is already determined by an earlier operand. This differs from languages like C, which use short-circuit evaluation. Consequently, you cannot safely do something like:
IF ADR(RefInStruct) <> 0 AND RefInStruct.Enable THEN
RefInStruct.Value := RefInStruct.Value + 1;
END_IF
In the example above, if ADR(RefInStruct) = 0
, the second part of the condition (RefInStruct.Enable
) would still be evaluated, causing an invalid access. Instead, perform the checks in separate statements.
3. Use an Input Variable of Type UDINT to pass the address as integer
- Passing the Pointer as an Integer
You can pass a pointer as aUDINT
to your function or function block. This pattern is often seen in B&R libraries. - Accessing the Pointer Internally
To dereference this pointer you need to declare an internal reference variable and link it to the integer pointer using theACCESS
directive. For example:
IF ipUsint <> 0 THEN // Check for a non-zero pointer
InternalRefToUsint ACCESS ipUsint; // Link the reference to the address
DereferencedUsint := InternalRefToUsint; // Implicitly dereference via assignment
END_IF
-
Checking for a Null Pointer
Since the address is passed as an integer, you can simply check if it’s non-zero—similar to how it’s done in C/C++. -
Lack of Compile-Time Type Checking
Because you’re passing a raw integer, there is no automatic validation to ensure the pointer’s type matches your reference type. If you accidentally pass the wrong pointer or point to invalid data, you might encounter runtime errors or memory access violations.
As I couldn’t find this information in the official documentation, I decided to share it here, hoping it will help others in the future.