TL;DR:在 CoDeSys v3 中可以使用 Totes,而且非常简单。
在 CoDeSys 中,“函数”实际上是存储在函数表中的函数指针。
在 CodeSys v2 中,要获取必须使用的函数的地址INDEXOF(F_MyFunction)
,这提供了函数指针在函数表中的索引。获取表的地址对于读者来说是一项练习(可以通过一些体操来检索它)。
在 CoDeSys v3 中,ADR
作品而不是INDEXOF
, 因此ADR(F_MyFunction)
给出指向的函数指针的地址F_MyFunction
's code!
你猜怎么着:你可以设置该函数指针,并且F_MyFunction(...)
只是通过该函数指针进行调用。
就是这么简单。
因此,要进行间接函数调用,您所需要做的就是声明一个虚拟“函数”,它实际上就像一个可设置的函数指针!
假设我们有两个要间接调用的目标函数:
FUNCTION F_Add1: INT
VAR_INPUT
param : INT;
END_VAR
F_Add1:= param + 1;
END_FUNCTION
FUNCTION F_Add2: INT
VAR_INPUT
param : INT;
END_VAR
F_Add2:= param + 2;
END_FUNCTION
然后我们定义一个“函数指针”,它必须与间接调用的函数具有相同的签名:
FUNCTION FPTR_Add : INT
VAR_INPUT
param : INT;
END_VAR
END_FUNCTION
我们还可以有一个分配给函数指针的助手:
F_FPTR_Assign
VAR_INPUT
dst : POINTER TO PVOID;
src : POINTER TO PVOID;
END_VAR
dst^ := src^;
END_FUNCTION
最后,我们来做一些间接调用:
// should return 3 if indirect calls work
FUNCTION F_Test : INT
VAR
val : INT;
END_VAR
F_FPTR_Assign(ADR(FPTR_Add), ADR(F_Add1));
// FPTR_Add points to F_Add1
val := FPTR_Add(val);
// here val has value 1
F_FPTR_Assign(ADR(FPTR_Add), ADR(F_Add2));
// FPTR_Add points to F_Add2
val := FPTR_Add(val);
// here val has value 3
F_Test := val;
END_FUNCTION
这种方法的唯一缺点是调试器不检查函数指针的动态值,因此步入表现得像跨过去。解决方法是在目标函数中设置断点,然后步入 and 跨过去将停在那里。
还有其他方法可以实现此效果,例如通过直接操作堆栈帧,因此即使这种方法由于 CoDeSys 中的某些更改而停止工作,也有其他方法可以实现。