如你所知TCL有一些数学函数,如 sin , cos 和 hypot ,在 expr中调用带()括号的命令如下:
puts [expr sin(1.57)]
现在我如何使用TCL library functions添加一个函数,以便以完全相同的方式调用它,并且正在执行某些 proc 定义的操作。
我想澄清一下我的问题。假设有一个proc(字符串)如下:
proc add { a b } { return [expr $a+$b] } ;# string of a proc
我的C ++代码中也有一个TCL解释器。现在我想得到一个proc 的字符串,并且运行时将一个名为 add 的函数注册到tcl::mathfunc namespace(我想我应该使用Tcl_CreateObjCommand)所以我可以打电话给以下人员:
puts [expr add(1.57, 1.43)]
如何做到这一点。你能写一个简单的例子吗?我在TCL文档和书籍中找不到任何描述this command用法的例子。
答案 0 :(得分: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,如此处所示)。
从C ++完成所有这些操作也非常实用,但请记住,Tcl是 C 库,因此它们必须是函数(不是方法,不是没有适配器),而且它们需要C链接。
要从C(或C ++)获取过程的主体,到目前为止最简单的机制是使用Tcl_Eval
运行一个简单的脚本来运行info body theCmdName
。程序实现非常复杂,因此它们的接口纯粹是在脚本级别(除非你真的用Tcl纠缠自己,而不是非常明智)。