2

如您所知,TCL 有一些数学函数,例如sincoshypot,它们在expr命令中使用()大括号调用,如下所示:

puts [expr sin(1.57)]

现在我如何使用 TCL库函数添加一个函数,以便以完全相同的方式调用它,并且正在执行某个proc定义的操作。

我想澄清我的问题。假设有一个proc(字符串)如下:

proc add { a b } { return [expr $a+$b] } ;# string of a proc

我的 C++ 代码中还有一个 TCL 解释器。现在我想获取proc和运行时的字符串,将一个名为add的函数注册到tcl::mathfunc 命名空间(我想我应该使用Tcl_CreateObjCommand),以便我可以调用以下内容:

puts [expr add(1.57, 1.43)]

如何做到这一点。请你写一个简单的例子。我在 TCL 文档和书籍中找不到任何描述此命令用法的示例。

4

1 回答 1

3

从 C 创建一个函数并不难。为此,您必须编写将执行该操作的命令的实现,并将该实现注册为正确命名空间中的命令。(在 8.4 和之前的版本中,功能是通过一个单独的接口完成的,使用起来有点麻烦;该机制在 8.5 中进行了全面检修。)

命令实现

注意签名是定义的,ignored这里不使用参数。(当您想要执行诸如将命令绑定到对象之类的操作时,它真的很棒void *—但它根本不需要进行加法。)

static int AddCmd(ClientData ignored, Tcl_Interp *interp, int objc,
        Tcl_Obj *const objv[]) {
    double x, y, sum;

    /* First, check number of arguments: command name is objv[0] always */
    if (objc != 3) {
        Tcl_WrongNumArgs(interp, 1, objv, "x y");
        return TCL_ERROR;
    }

    /* Get our arguments as doubles */
    if (    Tcl_GetDoubleFromObj(interp, objv[1], &x) != TCL_OK ||
            Tcl_GetDoubleFromObj(interp, objv[2], &y) != TCL_OK) {
        return TCL_ERROR;
    }

    /* Do the real operation */
    sum = x + y;

    /* Pass the result out */
    Tcl_SetObjResult(interp, Tcl_NewDoubleObj(sum));
    return TCL_OK;
}

不用担心它在这里分配了一个值;Tcl 有一个非常高性能的自定义内存管理器,这使得它成为一种廉价的操作。

命令注册

这通常在作为 Tcl 包定义的一部分注册作为整个应用程序初始化的一部分调用的初始化函数内完成。如果您Tcl_CreateInterp手动调用,您也可以直接执行此操作。你做什么取决于你是如何与 Tcl 集成的,这本身就是一个很大的话题。所以我将展示如何创建一个初始化函数;在所有情况下,这通常都是一个好的开始。

int Add_Init(Tcl_Interp *interp) {
    /* Use the fully-qualified name */
    Tcl_CreateObjCommand(interp, "::tcl::mathfunc::add", AddCmd, NULL, NULL);
    return TCL_OK;
}

第一个NULL是作为第一个 ( ClientData) 参数传递给实现的值。第二个是处理的回调ClientData(如果不需要操作,则为 NULL,如此处)。

Doing all this from C++ is also quite practical, but remember that Tcl is a C library, so they have to be functions (not methods, not without an adapter) and they need C linkage.


To get the body of a procedure from C (or C++), by far the easiest mechanism is to use Tcl_Eval to run a simple script to run info body theCmdName. Procedure implementations are very complex indeed, so the interface to them is purely at the script level (unless you actually entangle yourself far more with Tcl than is really wise).

于 2012-06-11T23:37:58.663 回答