In CODESYS, you are generally allowed to use the same identifier for different elements. For example, a POU and a variable can be named the same. However, you should avoid this practice in order to prevent confusion.
Negative example: In the following code snippet, a local function block instance has the same name as a function:
Example
FUNCTION YYY : INT ; END_FUNCTION FUNCTION_BLOCK XXX ; END_FUNCTION_BLOCK PROGRAM PLC_PRG VAR YYY : XXX; END_VAR YYY(); END_PROGRAM
In such a case as this, it is unclear whether the instance or the function is called in the program.
To make sure that names are always unique, you should follow naming conventions, such as certain prefixes for variables. Rules for assigning identifiers can be found in the "Identifiers" chapter of the help.
Naming conventions can be checked automatically using the static code analysis of
CODESYS. Static code analysis could also detect the duplicate use of the name YYY
and report it as an error.
The consistent use of the attribute qualified_only
for enumerations and global variable lists and the use of qualified libraries can
also prevent ambiguous situations.
To make sure that a POU of the same name in the “Devices” view is not called when a POU in the “POUs” view is called, the operator __POOL
should be prepended (for example, svar_pou := __POOL.POU();
) when the name of the POU is called.
Shadowing: The compiler does not report any errors or warnings if the same identifier is used for different elements. Instead, the compiler searches the code in a specific order for the declaration of the identifier. If a declaration is found, then the compiler does not search for any other declarations elsewhere. If other declarations do exist, then they are "shadowed" for the compiler. The following section describes the shadowing rules (that is, the search order that the compiler uses when searching for the declaration for identifiers). The section "Ambiguous access and qualified access" provides ways to prevent ambiguous access and bypass shadowing rules.
Search order in the application
When the compiler encounters a single identifier in the code of an application, it searches for the corresponding declaration in the following order:
1. Local variables of a method
2. Local variables in the function block, program, or function, and in any base function blocks
3. Local methods of the POU
4. Global variables in the application, if the qualified_only
attribute is not set in the variable list where the global variables are declared
5. Global variables in a parent application, if the qualified_only
attribute is not set in the variable list where the global variables are declared
6. Global variables in referred libraries when neither the library nor the variable list requires qualified access
7. POU or type names from the application (that is, names of global variable lists, function blocks, and so on)
8. POU or type names from a parent application
9. POU or type names from a library
10. Namespaces of locally referred libraries and libraries that are published by libraries
11. Global variables in the “POUs” view, unless the qualified_only
attribute is set in the variable list where they are declared
12. POU or type names from the “POUs” view (that is, names of global variable lists, function blocks, and so on)
Libraries that are inserted in the Library Manager of the “POUs” view are mirrored in the Library Manager in all applications in the project with the appropriate placeholder resolution. These libraries then form a common namespace with the libraries in the application. Therefore, there is no shadowing of libraries in the pool by libraries in the application.
Search order in the library
When the compiler encounters a single identifier in the code of a library, it searches for the corresponding declaration in the following order:
1. Local variables of a method
2. Local variables in the function block, program, or function, and in any base function blocks
3. Local methods of the POU
4. Global variables in the local library, if the qualified_only
attribute is not set in the variable list where the global variables are declared
5. Global variables in referred libraries when neither the library nor the variable list requires qualified access
6. POU or type names from the local library (that is, names of global variable lists, function blocks, and so on)
7. POU or type names from a referred library
8. Namespaces of locally referred libraries and libraries that are published by locally refereed libraries
Ambiguous access and qualified access
Despite these search orders, ambiguous access can still occur. For example, this is
the case when a variable with the same name exists in two global variable lists that
do not require qualified access. Such a case is reported by the compiler as an error
(for example: ambiguous use of the name XXX
).
This kind of ambiguous usage can be made unique by means of qualified access, for
example by accessing via the name of the global variable list (example: GVL.XXX
).
Qualified access can also always be used to avoid shadowing rules.
-
The name of the global variable list can be used to uniquely access a variable in the list.
-
The name of a library can be used to uniquely access elements in the library.
-
The
THIS
pointer be used to uniquely access variables in a function block, even if a local variable with the same name exists in a method of the function block.
To find the declaration location of an identifier at any time, use the command “Edit Browse Go to Definition”. This can be especially helpful if the compiler produces an apparently obscure error message.
Searching in instance paths
The search orders described above do not apply to identifiers that exist as components in an instance path or to identifiers that are used as inputs in calls.
For access of the following type yy.component
, it depends on the entity described by yy
where the declaration of component
is searched for.
If yy
denotes a variable with a structured data type (that is, type STRUCT
or UNION
), then component
is searched for in the following order:
-
Local variables of the function block
-
Local variables of the base function block
-
Methods of the function block
-
Methods of the base function block
If yy
denotes a global variable list or a program, then component
is searched for in this list only.
If yy
denotes a namespace of a library, then component
is searched for in this library exactly as described in the section above "Search
order in the library".
Only in the second instance does the compiler decide whether access to the found element is granted (that is, whether the variable is only locally accessible, or whether a method is private). If access is not allowed, an error is issued.