从Tcl_Obj获取指针的地址

nhaq1z21  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(96)

关于我的question我现在尝试在另一个函数中获取这个值。
到目前为止,我主要使用Tcl_Obj来检索:

  • char
  • 列表值
  • 等等

但不是指针地址。根据Tcl API,这样的函数不存在(我认为.)。
网上没有太多的例子(最重要的是,我不知道在哪里/找什么),我想这个页面(Tcl Handles)可能会有帮助,但我不确定。
谁能给我给予一下?

编辑(在@n的评论之后。可能是AI):

critcl::cproc initContext {Tcl_Interp* interp} ok {
    Context ctx;

    Init(&ctx);
    // printf("pointer %p\n", &ctx);

    char hexstr[24];
    sprintf(hexstr,"%p", (void*)&ctx);

    Tcl_SetObjResult(interp, Tcl_NewStringObj(hexstr, -1));

    return TCL_OK;
}

critcl::cproc useContext {Tcl_Interp* interp Tcl_Obj* ctxObj} ok {

    int len;
    char *strPointer;

    // Gets context pointer as a string
    strPointer = Tcl_GetStringFromObj(ctxObj, &len);

    // @Donal Fellows comment : 
    // "convert a pointer to an integer
    // (cast to intptr_t first) and an integer to a pointer"
    // I would like to reuse this context in this C function like this
    // showContext(&ctx);

    return TCL_OK;
}
# Tcl code
set ctx [initContext] ; # Gets context...
useContext $ctx ; # Using context

编辑2(在@n的评论之后。可能是AI。一个最小可重复的例子):

我的C代码可以用:

void testContext() {
    Context ctx;

    if (Init(&ctx) != SUCCESS)
      return;

    showContext(&ctx);
}

注:* 我不知道这是否重要,我使用critcl(我认为哲学是一样的,我希望如此!)*.

fbcarpbf

fbcarpbf1#

你可以将一个指针转换成一个整数(先转换成intptr_t),然后将一个整数转换成指针,这样就可以了。但它非常不安全;没有好的办法直接验证这些东西!但有些事你可以做。
最低级别的验证是用名称来假装指针编号(可能是从它所指向的事物的名称派生出来的?)这样你就不会不小心把它们完全弄混了;你可以在解析值的时候很容易地检查它。许多Tcl扩展都是这样做的。
更高级别的验证是在Tcl解释器中存储一个哈希表(作为命令的客户端数据或通过Tcl_SetAssocData),并使用它来检查来自脚本的值是否是给它的值,并且还没有被无效(当你释放它指向的东西时,你通常会无效)。像这样指针可以通过脚本,但只能作为不透明值。(我在那个wiki页面上的旧代码正在做一种更高级的形式,将Map缓存在句柄标记本身中。)Tcl在Windows上为它的原生通道句柄做了一些非常类似的事情(其他平台使用FD代替)。
(If你有这样一个表,它使列出当前已知的值成为一种简单的内省起点。)
对此的一个轻微扩展是使用计数器(或者RNG,如果您喜欢)来生成这些句柄名称的变化部分,而不是指针部分本身。就像你不使用安全检查就不可能返回Map...但通常没这个必要这就是合成通道(请参见chan create)创建其句柄的方式。(TclOO * 似乎 * 这样做,但做了其他事情;里面有更多的活动部件)。
在这方面需要注意的主要事情是,当您删除它指向的值(或以其他方式使其不可用)时,您需要停止Map的工作。Tcl不提供垃圾收集的帮助(你可以在某种程度上欺骗它,相当多的代码是这样做的,但它在形式上是脆弱的,不受支持)。明确删除是官方首选的方法。

pvabu6sv

pvabu6sv2#

你不需要“指针的地址”。你只需要一个指针值。
打印一个指向一个字符串的指针,其大小为sprintf(buffer, "%p", pointer),然后将其转换为Tcl对象。
逆操作将是sscanf(buffer, "%p", &pointer)从Tcl对象获取一个字符串并读取它:

char* buffer = Tcl_GetString(obj);
void* ponter;
if (buffer == NULL || sscanf(buffer, "%p", &pointer) != 1)
{
    // report error
}

Context* pCtx = (Context*)pointer;

下面是一个完整的测试工作的Tcl扩展,使用上述方法。请注意上下文是静态的,而不是任何命令的本地上下文。您可能需要动态地分配它,并使用Tcl对象生存期管理来管理它的生存期,但这超出了本答案的范围。

#include <tcl.h>

typedef struct Context
{
    int hour, minute;
} Context;

Context ctx = {7, 40 };

 static int 
 Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
 {
    char hexstr[24];
    sprintf(hexstr,"%p", (void*)&ctx);

    Tcl_SetObjResult(interp, Tcl_NewStringObj(hexstr, -1));
     
    return TCL_OK;
 }

 static int 
 Bye_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
 {
     if (objc != 2)
     {
         Tcl_AppendResult(interp, "wrong # args", NULL);
         return TCL_ERROR;
     }
     char* buffer = Tcl_GetString(objv[1]);
     void* pointer = NULL;
     if (buffer == NULL || sscanf(buffer, "%p", &pointer) != 1)
     {
         Tcl_AppendResult(interp, "bad scan", NULL);
         return TCL_ERROR;
     }
     Context* pCtx = (Context*)pointer;

     Tcl_SetObjResult(interp, Tcl_ObjPrintf("The departure is at %d:%d", pCtx->hour, pCtx->minute));
     return TCL_OK;
 }

 /*
  * Hello_Init -- Called when Tcl loads your extension.
  */
 int DLLEXPORT
 Hello_Init(Tcl_Interp *interp)
 {
     if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
         return TCL_ERROR;
     }
     /* changed this to check for an error - GPS */
     if (Tcl_PkgProvide(interp, "Hello", "1.0") == TCL_ERROR) {
         return TCL_ERROR;
     }
     Tcl_CreateObjCommand(interp, "hello", Hello_Cmd, NULL, NULL);
     Tcl_CreateObjCommand(interp, "bye", Bye_Cmd, NULL, NULL);
     return TCL_OK;
 }

相关问题