从 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).