Checking for Null Pointers in IEC Functions and Function Blocks

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 use ADR() 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 a UDINT 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 the ACCESS 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.

4 Likes

this will definitely help, thanks for sharing :wink:

Using ACCESS inside a function or function block is not supported as of my knowledge.

As I know you can pass UDINT variable in VAR_INPUT then declare a reference variable in VAR then you can use ACCESS like this :

VAR_INPUT
	pText : UDINT; (*Address of the string you need to test*)
END_VAR
VAR
	pChar : REFERENCE TO USINT; (*Internal pointer to a Char*)
END_VAR
FUNCTION test

	pChar ACCESS pText

END_FUNCTION

I used this in a function to determine if a string is numerical for example.

2 Likes

Thank you for this hint. :slightly_smiling_face:
Did some tests and can confirm this.
Will update the initial post accordingly.

1 Like

I don’t agree with this statement.
In my experience, no type check is carried out when a variable is passed using ‘Reference’. Unfortunately, the compiler accepts the wiring with the address of a variable of any type.

The only way to enforce a type check is declaring the variable as In-Out.

2 Likes

@Thomas - Of course you are right.
Thank you for pointing this out. I updated the post.

1 Like