【问题标题】:How to send struct data type variables from c to tcl struct data type variables?如何将 struct 数据类型变量从 c 发送到 tcl struct 数据类型变量?
【发布时间】:2021-11-18 18:22:55
【问题描述】:

我无法找到将 c struct 数据类型变量链接到 tcl struct 数据类型变量的方法。 我想将结构变量数据从 c 编程发送到 tcl .. 任何人都可以对此提出建议吗?

【问题讨论】:

    标签: c tcl sharing


    【解决方案1】:

    Tcl 没有这样的结构,所以你需要考虑你想要做什么。关键的选择与我们讨论了多少结构以及这些实体需要有多活跃有关。

    将结构链接到数组

    如果您只是在谈论映射单个结构实例,您可以使用Tcl_LinkVar() 绑定原始C 类型(例如结构的成员),并拥有Tcl 侧变量都是单个数组的元素。这对于系统控制之类的事情来说非常棒

    struct foo_t {
        int bar;
        double grill;
    }
    
    // NEEDS to be at file or global scope!
    // Or to something with at least the same lifetime as the Tcl interpreter.
    // MUST NOT be stack-allocated or Bad Things Happen™
    struct foo_t foo;
    
    // And then to bind the elements in your Init function, and omitting some casts
    Tcl_LinkVar(interp, "foo(bar)", &foo.bar, TCL_LINK_INT);
    Tcl_LinkVar(interp, "foo(grill)", &foo.grill, TCL_LINK_DOUBLE);
    

    虽然 双向绑定,但如果您想绑定其中的许多,它就不会那么好用了。理论上它可以工作,但它真的很乱。

    结构和 Tcl 值之间的转换

    如果您想做相当于将结构体作为值传递,可以使用三种基本方法。这些是将它们映射为列表,将它们映射为 dicts,并执行自定义操作。在所有这些情况下,如果你创建一些辅助函数真的很有帮助,我称之为NewFooObj()GetFooFromObj()

    对于列表:

    Tcl_Obj *NewFooObj(struct foo_t *fooPtr) {
        Tcl_Obj *objs[2];
        
        objs[0] = Tcl_NewIntObj(fooPtr->bar);
        objs[1] = Tcl_NewDoubleObj(fooPtr->grill);
        return Tcl_NewListObj(2, objs);
    }
    
    int GetFooFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, struct foo_t *fooPtr) {
        int objc;
        Tcl_Obj **objv;
        if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
            return TCL_ERROR;
        }
        if (objc != 2) {
            Tcl_AppendResult(interp, "foo objects need two elements", NULL);
            return TCL_ERROR;
        }
        if (Tcl_GetIntFromObj(interp, objv[0], &fooPtr->bar) != TCL_OK) {
            return TCL_ERROR;
        }
        if (Tcl_GetDoubleFromObj(interp, objv[0], &fooPtr->grill) != TCL_OK) {
            return TCL_ERROR;
        }
        return TCL_OK;
    }
    

    对 dicts 做同样的事情是对你如何使用 Tcl_DictObjPut()Tcl_DictObjGet() 的一个练习(但你在阅读时需要小心一点,因为键本身就是引用计数的对象)。

    Tcl_Obj *NewFooObj(struct foo_t *fooPtr) {
        Tcl_Obj *objPtr = Tcl_NewDictObj();
        Tcl_DictObjPut(NULL, objPtr, Tcl_NewStringObj("bar", -1),
                Tcl_NewIntObj(fooPtr->bar));
        Tcl_DictObjPut(NULL, objPtr, Tcl_NewStringObj("grill", -1),
                Tcl_NewDoubleObj(fooPtr->grill));
        return objPtr;
    }
    
    int GetFooFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, struct foo_t *fooPtr) {
        Tcl_Obj *barNameObj = Tcl_NewStringObj("bar", -1);
        Tcl_Obj *grillNameObj = Tcl_NewStringObj("grill", -1);
        Tcl_Obj *value;
        int result = TCL_ERROR;
    
        Tcl_IncrRefCount(barNameObj);
        Tcl_IncrRefCount(grillNameObj);
        if (Tcl_DictObjGet(interp, objPtr, barNameObj, &value) == TCL_OK
                && Tcl_GetIntFromObj(interp, value, &foo->bar) == TCL_OK
                && Tcl_DictObjGet(interp, objPtr, grillNameObj, &value) == TCL_OK
                && Tcl_GetDoubleFromObj(interp, value, &foo->grill) == TCL_OK) {
            result = TCL_OK;
        }
        Tcl_DecrRefCount(barNameObj);
        Tcl_DecrRefCount(grillNameObj);
        return result;
    }
    

    函数组具有传统的 Tcl 引用计数语义(创建函数提供零引用计数值,读取函数不操作可见引用计数)。

    至于第三个选项……是的,你也可以编写你自己的自定义对象类型,它可以使用你想要的任何字符串和内部表示(你可能希望引用堆分配的 struct foo_t 作为内部表示)。如果您走这条路,我们建议您这样做,以便您可以解析纯字符串以获得您的类型(不允许这使它们变得神奇且可能很脆弱)并拥有它,以便您可以始终如一地往返。

    活动结构

    如果你想拥有许多实例并且让这些实例是可修改的(并且不仅仅是传递它们;如果只是传递,那么你可以通过 Tcl 代码抛出地址,这在形式上是不安全的但非常方便,并且可以通过句柄化来确保安全,这在许多方面都是活动 Tcl 实体(如命令、变量和通道)的工作方式——将事物转换为句柄使用哈希表在名称和指针之间进行映射)然后你可能有转到 TclOO 或自定义命令系统之类的东西。我认为这个答案已经足够长了,所以再问一次你是否需要这种复杂程度。

    【讨论】:

    • 我还应该提到,您也可以将结构的内存视为字节数组(或反之亦然),并以这种方式传递事物。这是特定于平台的,但在您希望将结构视为纯可复制值时可能是一种有用的技术。
    • 直到关于Tcl_LinkVar()。我需要回去重写一些代码......
    • (返回一个指向底层 C 变量的 void 指针及其链接类型的函数,方便使用)
    猜你喜欢
    • 1970-01-01
    • 2013-08-12
    • 2021-03-19
    • 2021-03-18
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多