你能给我一个例子来说明如何在我的库中声明一个指向函数的指针吗?以及如何将指向函数的指针传递给我的外部库?
3 回答
TL;DR:在 CoDeSys v3 中,手提袋可能而且非常容易。
在 CoDeSys 中,“函数”实际上是存储在函数表中的函数指针。
在 CodeSys v2 中,要获取必须使用的函数的地址INDEXOF(F_MyFunction)
,这提供了函数表中函数指针的索引。获取桌子的地址是,呃,读者的练习(可以通过一些体操来检索它)。
在 CoDeSys v3 中,ADR
可以代替INDEXOF
,从而ADR(F_MyFunction)
为您提供指向F_MyFunction
的代码的函数指针的地址!
猜猜看:您可以设置该函数指针,并且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
这种方法的唯一缺点是调试器不检查函数指针的动态值,因此step into的行为类似于step over。解决方法是在目标函数中设置断点,然后step into和step over都会停在那里。
还有其他实现这种效果的方法,例如通过直接操作堆栈帧,因此即使这种确切的方法由于 CoDeSys 中的一些变化而停止工作,也有其他方法可以做到这一点。
编辑 09/2020:查看本主题中的另一个答案并忘记这个!
在基于 Codesys 的平台中,可以创建指向数据类型或功能块的指针。在 TwinCAT 3 中也可以创建函数指针,但不能在 PLC 程序中调用。函数指针只能作为外部库组件的参数给出。
指针是可能的。要codesys
创建一个指针,codesys
你会做
VAR
pVar : POINTER TO BYTE;
tempVar : BYTE;
derefereceVar : BYTE;
END_VAR
//get a pointer to the byte variable
pVar := ADR(tempVar);
要取消引用该指针,您将
derefereceVar := tempVar^;
因此,如果您想将指针作为函数的参数,您可以传入pVar
或ADR(tempVar)
在上面的示例中传递给以 aPOINTER_TO_BYTE
作为类型的函数的参数。