如何在 Codesys v3 中创建指向函数的指针

Kso*_*sem 3 c codesys iec61131-3

你能给我一个例子来说明如何在我的库中声明函数指针吗?如何将函数指针传递给外部库?

Rei*_*ica 6

TL;DR:在 CoDeSys v3 中可以使用 Totes,而且非常简单。

在 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
Run Code Online (Sandbox Code Playgroud)

然后我们定义一个“函数指针”,它必须与间接调用的函数具有相同的签名:

FUNCTION FPTR_Add : INT
VAR_INPUT
  param : INT;
END_VAR
END_FUNCTION
Run Code Online (Sandbox Code Playgroud)

我们还可以有一个分配给函数指针的助手:

F_FPTR_Assign
VAR_INPUT
  dst : POINTER TO PVOID;
  src : POINTER TO PVOID;
END_VAR
dst^ := src^;
END_FUNCTION
Run Code Online (Sandbox Code Playgroud)

最后,我们来做一些间接调用:

// 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
Run Code Online (Sandbox Code Playgroud)

此方法的唯一缺点是调试器不会检查函数指针的动态值,因此单步执行的行为类似于step over。解决方法是在目标函数中设置断点,然后单步执行单步执行都会停止在那里。

还有其他方法可以实现此效果,例如通过直接操作堆栈帧,因此即使该方法由于 CoDeSys 中的某些更改而停止工作,也有其他方法可以实现。