【发布时间】:2017-03-31 11:01:55
【问题描述】:
你能举个例子说明如何在我的库中声明一个指向函数的指针吗?以及如何将指向函数的指针传递给我的外部库?
【问题讨论】:
标签: c codesys iec61131-3
你能举个例子说明如何在我的库中声明一个指向函数的指针吗?以及如何将指向函数的指针传递给我的外部库?
【问题讨论】:
标签: c codesys iec61131-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 中的一些变化而停止工作,也有其他方法可以做到这一点。
【讨论】:
在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 作为类型的函数的参数。
【讨论】:
编辑 09/2020:请参阅本主题中的另一个答案并忘记这个!
在基于 Codesys 的平台中,可以创建指向数据类型或功能块的指针。在 TwinCAT 3 中也可以创建函数指针,但不能在 PLC 程序中调用。函数指针只能作为外部库组件的参数。
【讨论】: