如何在codesys v3中创建指向函数的指针
Posted
技术标签:
【中文标题】如何在codesys v3中创建指向函数的指针【英文标题】:how to create pointer to function in codesys v3 【发布时间】:2017-03-31 11:01:55 【问题描述】:你能举个例子说明如何在我的库中声明一个指向函数的指针吗?以及如何将指向函数的指针传递给我的外部库?
【问题讨论】:
【参考方案1】: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 中的一些变化而停止工作,也有其他方法可以做到这一点。
【讨论】:
非常感谢。这在 Beckhoff 的 TwinCat3 中也能完美运行! @dotKokott 您可能需要联系您的 Beckhoff 代表并告诉他们,在当今时代,对此类体操的需求是不可接受的。函数指针或等价物是任何现代编程系统的基本功能,而 TC3 不正式支持它们的事实就像是一记耳光。软件工程社区需要对 CoDeSys 和 Beckhoff 等供应商施加巨大压力,这些供应商的开发工具停留在上世纪下半叶。如果他们听到的只是蟋蟀,他们什么都不会改善。我们需要改变。请务必与他们联系。 我个人参与了 Beckhoff TC3 PLC 运行时的大规模迁移,正是因为他们的开发系统非常糟糕,而且在各方面都如此落后,以至于这是对一个人的智力的侮辱。任何软件开发都要求源代码与 git 兼容,并且工具易于自动化。他们提供了一些口头上的服务,但与任何其他现代开发工具相比,这都是一个巨大的谎言,完全倒退。 CoDeSys 和 TC3 都用随机垃圾污染源文件夹,这是第一个大禁忌。从那里只有下坡路【参考方案2】:在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)
传递给以 POINTER_TO_BYTE
作为类型的函数的参数。
【讨论】:
感谢您的回复,但我喜欢创建指向函数的指针,例如在 c 语言中我们这样做:int sum (int num1, int num2) return sum1+sum2; int main() int (*f2p) (int, int); f2p = 总和; int op1 = f2p (10, 13); int op2 = sum (10, 13); printf("输出 1 – 通过指针调用函数:%d",op1); printf("Output2 – 用于直接函数调用:%d", op2);返回0;所以我喜欢在 codesys 中做同样的事情来将此指针发送到我的外部库【参考方案3】:编辑 09/2020:请参阅本主题中的另一个答案并忘记这个!
在基于 Codesys 的平台中,可以创建指向数据类型或功能块的指针。在 TwinCAT 3 中也可以创建函数指针,但不能在 PLC 程序中调用。函数指针只能作为外部库组件的参数。
检查这个: https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/136447627.html&id=4296747249216071915
【讨论】:
刚刚注意到我收到的这个答案很少有人反对。只是想知道回答问题是否有问题。 Codesys 3的PLC代码中不能做函数指针。 但是您可以,而且 ADR 就是您的做法 - 您链接到的 ADR 文档中没有任何内容与此相反。他们没有记录 ADR 的结果,即如何使用它。这留给自己的努力,但很容易弄清楚。您在 32 位或 64 位内核模式下运行,具有平坦的内存,可以这么说,世界是敞开的。调查内存内容没什么大不了的。 感谢您对这个话题的回答,这很鼓舞人心!以上是关于如何在codesys v3中创建指向函数的指针的主要内容,如果未能解决你的问题,请参考以下文章