如果VAR_INPUT是INTERFACE类型,则值是按引用传递还是按值传递?

时间:2019-05-20 01:27:59

标签: twincat codesys iec61131-3

在TwinCAT和CodeSys IEC-61131编程环境中,可以使用VAR_INPUT作为类型规范声明POU INTERFACE。我相信TwinCAT和CoDeSys对接口的支持是对标准IEC-61131语言定义的扩展。

问题1:调用POU时,接口VAR_INPUT是否具有传递值(即在每次执行FB时复制输入FB的状态)或传递引用语义?

问题2:在哪里指定或记录此行为?

2 个答案:

答案 0 :(得分:1)

接口类型本身是一个值,但是它不包含它所引用的功能块。它被实现为指向实例的vtable-pointer的指针。如果它是对实现接口的功能块的引用,则使用它,但是返回的地址是功能块的地址 NOT (这是关键的区别)。那是因为实现了:

                                    FB Instance
                                         |
interface (PVOID) ------+        * PVOID vtable 1       +----> VTABLE 3
                        +------> * PVOID vtable 2  -----+        |
                                 *     ...                   * method 1
                                 * PVOID vtable n            *   ...
                                 * data fields               * method m

因此,如果您读取接口的内容,则会在功能块实例内的某个位置获得一个地址,该地址就是该实例内vtable指针的地址。特定的vtable是实现接口方法(即与接口兼容)的那个。

对于某些类型的FB_MyFB,我们可以检查是否是如此:

INTERFACE I_Derived EXTENDS __SYSTEM.QueryInterface
END_INTERFACE

FUNCTION_BLOCK FB_MyFB IMPLEMENTS I_Derived
...
END_FUNCTION_BLOCK

FUNCTION F_CheckInterfaceRange(fb : REFERENCE TO FB_MyFB) : BOOL
VAR
  ifc : I_Derived := fb;
  ifcval : POINTER TO PVOID := ADR(ifc);
END_VAR
ifcval := ifcval^;
F_CheckInterfaceRange := 
  ifcval >= ADR(fb) 
  AND_THEN ifcval <= (ADR(fb) + SIZEOF(FB_MyFB) - SIZEOF(PVOID)); 
END_FUNCTION

似乎不可能直接获取实例的地址。这很可能是一个任意限制:所有vtable指针都必须是有效的,并且可能属于某个内存区域,因此您可以想象从指向该接口的任何地方开始,然后从该接口向后走,直到停止获取有效的指针为止。这些就是界限。该实例以vtable指针开头,因此您将找到其中一个指针。然后检查指针在各种库FB类型的实例中的外观,然后查看指向vtables的外观,我确定会弹出一些有效的启发式方法,甚至可能不及{{1 }}。 CoDeSys 3代码生成器非常糟糕。

支持的方法是让FB实现扩展__QUERYINTERFACE的接口。然后,使用SYSTEM.__QueryInterface访问该接口以获取FB的__QUERYPOINTER的值。

您可以想象THIS看起来像:

__QUERYPOINTER

FUNCTION __QUERYPOINTER VAR_INPUT ifc : __SYSTEM.QueryInterface; ptr : REFERENCE TO PVOID; END_VAR ptr := ifc.__QUERYTHIS(); END_FUNCTION 接口实现了一种在FB实现的接口之间强制转换的方法,只要这两个接口都从__SYSTEM.QueryInterface派生,还可以实现一种方法(将其称为__SYSTEM.QueryInterface)返回__QUERYTHIS

该方法由编译器生成。

想象其余的实现有点像:

THIS

您可以类似地实现INTERFACE __SYSTEM.QueryInterface PROPERTY _This_ : POINTER TO BYTE METHOD _This__GET : POINTER TO BYTE // that's how CoDeSys 3 implements getters/setters END_PROPERTY ... END_INTERFACE FUNCTION BLOCK FB_Queryable IMPLEMENTS I_Queryable PROPERTY _This_ : POINTER TO BYTE METHOD _This__GET : POINTER TO BYTE _This_GET := THIS; END_METHOD END_FUNCTION_BLOCK (这并不容易,因为F_QueryInterface从编译器获得帮助):

__QUERYINTERFACE

答案 1 :(得分:0)

Interface变量在CoDeSys和TwinCAT中始终被视为引用。其中应包含VAR_INPUT变量。

TwinCAT referencescreen capture of linked documentation excerpt

CoDeSys referencescreen capture of excerpt from linked documentation