tcl语言中使用c语言_使用可加载的C模块构建tcl扩展

本文档介绍了如何使用C语言扩展Tcl,通过创建一个可加载的C模块,来实现Tcl解释器的扩展功能。文章讨论了如何定义函数原型、初始化数据结构,并提供了实现新功能的代码示例。最后,展示了如何在Tcl环境中使用这个新扩展。
摘要由CSDN通过智能技术生成

tcl语言中使用c语言

I hope you'll find this tutorial useful and interesting. So let's try to extend Tcl with a new package.  For anyone more deeply interested please check out the book "Practical Programming in Tcl and Tk". It's really one of the best written books about a programming language around.

我希望您会发现本教程有用且有趣。 因此,让我们尝试使用新软件包扩展Tcl。 对于任何更感兴趣的人,请阅读《 Tcl和Tk中的实用编程》一书。 实际上,这是有关编程语言的最好的书面书籍之一。

As you might know Tcl/Tk was developed to act as glue between C modules. And therefor one really can say interfacing C to Tcl/Tk is one of the easier things.

如您所知,Tcl / Tk被开发为充当C模块之间的粘合剂。 因此,确实可以说C与Tcl / Tk的接口是较容易的事情之一。

Today we built an extension with it's own package name and just one function to be called. I have used the netbeans (http://netbeans.org/features/index.html)  development environment to build this extension.

今天,我们使用自己的包名称和仅一个要调用的函数来构建扩展。 我已经使用netbeans( http://netbeans.org/features/index.html )开发环境来构建此扩展。

The end product of all extension usually is a shared library. One can even compile new function into tcl but I dare to say, this is not something for application development. So let's start with some prototypes:

所有扩展的最终产品通常是共享库。 甚至可以将新功能编译到tcl中,但我敢说,这不是应用程序开发所必需的。 因此,让我们从一些原型开始:

int Tcl_and_c_Adder(ClientData clientData,
              Tcl_Interp *interp,
              int objc, Tcl_Obj *CONST objv[]);

ClientDate will not get used but in fact it's a untyped pointer and can be used to hand in all kind if Data into the to be called function an example of it's usage can be found in the above mentioned book page 711 following.

ClientDate不会被使用,但实际上它是一个无类型的指针,如果将数据放入被调用的函数中,例如可以在上面提到的第711页的书中找到它,则它可以用于传递各种类型的指针。

For us much more interesting is interp because it represents the "tcl  interpreter". We can  have one or many of them and this is somewhat unique in Tcl/TK in other examples one can not have different interpreters. This again shows the main purpose of tcl.

对我们来说,更有趣的是interp,因为它代表“ tcl解释器”。 我们可以有一个或多个,这在Tcl / TK中有些独特,在其他示例中,不能有不同的解释器。 这再次显示了tcl的主要目的。

The objc is comparable to argc of the main function in C. It's a counter for the number of arguments. TclObj is comparable to argv. So this are just the parameters handed over to this function.

objc与C中主要函数的argc相当。它是参数数量的计数器。 TclObj与argv可比。 因此,这只是移交给该功能的参数。

Now there is a strict naming convention. In this example  I used Tcl_and_c_ as prefix. This is e.g needed to initialize the data-structures to "know" the new functionality. ans so we come to the next code piece:

现在有一个严格的命名约定。 在此示例中,我使用Tcl_and_c_作为前缀。 例如,这需要初始化数据结构以“知道”新功能。 回答,所以我们进入下一个代码段:

int Tcl_and_c_Init(Tcl_Interp *interp) {
  if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
    return TCL_ERROR;
  }
  Tcl_CreateObjCommand(interp, "fooadder", Tcl_and_c_Adder,
                       NULL, NULL);
  Tcl_PkgProvide(interp, "foo", "1.1");
  return TCL_OK;
}

This is all what is needed to make this  extension known to tcl. At first I require that at least tcl 8.1 is used. That means this extension will work for anything starting from Version 8.1. Currently I Have 8.4 installed. Anyway this code was written some time ago and still is  running. So that means we have some security  that our extensions will work for  some time. That is a good thing ;-)

这就是使tcl知道此扩展的全部所需。 首先,我要求至少使用tcl 8.1。 这意味着此扩展将适用于从8.1版开始的所有内容。 目前我已经安装了8.4。 无论如何,这段代码是前一段时间编写的,仍在运行。 因此,这意味着我们具有一定的安全性,我们的扩展可以使用一段时间。 这是一件好事 ;-)

Now there's one thing one has to keep in mind. All functions return Error codes this is comparable to the COM programming model. So we can not use the return value to give back calculated results. This also means one has to check the return values on the C side rigorously. If you forget that you will probably encounter strange bugs.

现在,必须记住一件事。 所有函数都返回错误代码,这与COM编程模型相当。 因此,我们不能使用返回值来返回计算结果。 这也意味着必须严格检查C侧的返回值。 如果您忘记了,您可能会遇到奇怪的错误。

Anyway let's see this:

无论如何,我们来看一下:

Tcl_CreateObjCommand(interp, "fooadder", Tcl_and_c_Adder,
                       NULL, NULL);

That all was boiler-plate code you just have to write it once and can use if for any extension. Now we come to the implementation of the new function:

所有这些都是样板代码,您只需编写一次即可,并且可以用于任何扩展。 现在我们来实现新功能:

int Tcl_and_c_Adder(ClientData clientData, Tcl_Interp *interp,
             int objc, Tcl_Obj *CONST objv[]) {
    int i_result = 0;
    Tcl_Obj *result;
    int ct = objc-1;
    int i;
    int i_rval;
    while (ct > 0){
        i_rval = Tcl_GetIntFromObj(interp, objv[ct], &i);
        if (TCL_OK != i_rval){
            return TCL_ERROR;
        }
        i_result += i;
        ct--;
     }
    result = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(result, i_result);
    return TCL_OK;

}

Now this is a handful of code. But it's not really "difficult" if you ever have done any kind of C programing with structures ;-)

现在,这是一些代码。 但是,如果您曾经用结构完成过任何形式的C编程,这并不是真的“困难” ;-)

I hope the names are self-explaining. Them most important are i_result (one can assume this will be some kind of number and Tcl_Obj *result). I've use the "modern" way of accessing tcl in an object oriented fashion. There's also the older "string-based" way of doing things. I for my part find my choice easier to understand and apply.

我希望名字能解释自己。 它们最重要的是i_result(可以假设这将是某种数字和Tcl_Obj * result)。 我已经使用“现代”方式以面向对象的方式访问tcl。 还有较旧的“基于字符串”的处理方式。 就我而言,我发现自己的选择更容易理解和应用。

I did not even forget  to check return values of the Tcl function which--surprise!--start with Tcl.  

我什至没有忘记检查从Tcl开始的Tcl函数的返回值(惊奇!)。

This:  i_rval = Tcl_GetIntFromObj(interp, objv[ct], &i); is the way to pick out certain kind of types  from the OBJC values of Tcl. Again if you know COM you can see the relationship the Tcl_Obj is a kind of variant and the names suggests it represents any kind of object.  

这:i_rval = Tcl_GetIntFromObj(interp,objv [ct],&i); 是从Tcl的OBJC值中选择某些类型的方法。 同样,如果您知道COM,则可以看到Tcl_Obj的关系是一种变体,并且名称表明它表示任何种类的对象。

As you can see I check the return value and as you can see also the content of objv[ct] is put into a long. And so we can see how result values are placed. They are in the last parameter so we have "out" parameter again this  is the same as in COM. After we picked the integer we just add the value into a normal variable. So what does this function really do?  It takes parameter and add them together. Not  directly rocket-science  as you probably agree. But the question is how to we get the result into Tcl?

如您所见,我检查了返回值,还如您所见,objv [ct]的内容放入了一个长整数。 这样我们就可以看到结果值的放置方式。 它们在最后一个参数中,因此我们再次具有“ out”参数,这与COM中的相同。 选择整数后,我们只需将值添加到普通变量中即可。 那么,此功能的真正作用是什么? 它需要参数并将它们添加在一起。 正如您可能会同意的那样,并非直接涉及火箭科学。 但是问题是如何将结果输入Tcl?

This is done here:

这是在这里完成的:

result = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(result, i_result);

Now you have to be a bit careful here. Obviously there is some internal Object kept for that in the Interpreter.  But we did not have allocated any space for the result because we just have a long. If you have some more complex structures you have to think of the clean-up procedures. However in our case we are really safe.

现在,您在这里必须小心一点。 显然,在解释器中为此保留了一些内部对象。 但是我们没有为结果分配任何空间,因为我们只有很长的空间。 如果您有一些更复杂的结构,则必须考虑清理程序。 但是对于我们来说,我们确实很安全。

We just place an integer value in the result and this does not need any "caring" at all. But if we'd have malloced pointers we'd better have the proper clean-up routines otherwise every call of the function will leak memory. And this can be quite a lot (think e.g of some tree)....

我们只是在结果中放置一个整数值,这根本不需要任何“照顾”。 但是,如果我们要分配指针,则最好有适当的清理例程,否则每次调用该函数都会泄漏内存。 这可能很多(例如考虑一些树)。

Now that's it.  Now you just have to compile this code properly and then you can call it.

就是这样。 现在,您只需要正确编译此代码,然后就可以调用它。

Here's how to use it on the tcl side:

这是在tcl端使用它的方法:

At first check the auto_path variable. Here I have:

首先,检查auto_path变量。 我在这里:

echo $auto_path
/usr/share/tcltk/tcl8.5 /usr/lib /usr/local/lib/tcltk /usr/local/share/tcltk /usr/lib/tcltk /usr/share/tcltk  /home/frido/programming/tcl/tcl_and_c/dist/Debug/GNU-Linux-x86
package require foo
1.1

Now, what a surprise, we got our 1.1 Version how nice ;-)

现在,出乎意料的是,我们的1.1版本真好;-)

And now let's roll:

现在开始吧:

fooadder 1 2 3
6

And there we have it a loadable new package with one very important function ;-)

在这里,我们有了一个具有一个非常重要功能的可加载新程序包;-)

I hope you'd enjoyed  this small tutorial. Would be nice to hear from you how you'd find it and if you see some more of that kind. I though showing such kind of example for a handful "scripting" languages might be "interesting"

希望您喜欢这个小教程。 希望能收到您的来信以及如果您看到更多类似的信息,将非常高兴。 我虽然展示了少数“脚本”语言的此类示例,但可能会“有趣”

#include <tcl.h>

int Tcl_and_c_Adder(ClientData clientData,
              Tcl_Interp *interp,
              int objc, Tcl_Obj *CONST objv[]);



int Tcl_and_c_Init(Tcl_Interp *interp) {
  if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
    return TCL_ERROR;
  }
  Tcl_CreateObjCommand(interp, "fooadder", Tcl_and_c_Adder,
                       NULL, NULL);
  Tcl_PkgProvide(interp, "foo", "1.1");
  return TCL_OK;
}


int Tcl_and_c_Adder(ClientData clientData, Tcl_Interp *interp,
             int objc, Tcl_Obj *CONST objv[]) {
    int i_result = 0;
    Tcl_Obj *result;
    int ct = objc-1;
    int i;
    int i_rval;
    while (ct > 0){
        i_rval = Tcl_GetIntFromObj(interp, objv[ct], &i);
        if (TCL_OK != i_rval){
            return TCL_ERROR;
        }
        i_result += i;
        ct--;
     }
    result = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(result, i_result);
    return TCL_OK;

}

翻译自: https://www.experts-exchange.com/articles/5147/Building-a-tcl-extension-with-a-loadable-C-module.html

tcl语言中使用c语言

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值