如何使用Critcl设置参数指向的数据?
我想用这样的话来表达: 我特别关注如何在Critcl中处理如何使用Critcl设置参数指向的数据?,tcl,Tcl,我想用这样的话来表达: 我特别关注如何在Critcl中处理int*grid对象字节?也许是定制的 与相关。该案例与Tcl的价值模型不太吻合。问题在于grid是(指向)可更新值集合的指针。在Tcl中,通常有两种建模方法: 作为不透明的物体 作为包含Tcl列表的变量(因为在模型术语中,Tcl值被认为是不可变的,而Tcl变量是可变的) 我将在下面描述如何实现这两种功能,但我猜您将把这些zOrder功能看作是一种独特的可变类型,而定制类型的额外一次性开销将更适合您 不透明(可变)对象 在处理不透明对象时
int*grid
<代码>对象<代码>字节?也许是定制的
与相关。该案例与Tcl的价值模型不太吻合。问题在于
grid
是(指向)可更新值集合的指针。在Tcl中,通常有两种建模方法:
critcl::ccode
命令中进行),该命令在名称和指针之间进行映射。这样做有点麻烦,但只需要构建两个哈希表
critcl::ccode {
static Tcl_HashTable *zOrderMap = NULL, *zOrderRevMap = NULL;
static Tcl_Obj *
MakeZOrderObj(int *zOrder) {
/* Initialize the two maps, if needed */
if (zOrderMap == NULL) {
zOrderMap = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(zOrderMap);
zOrderRevMap = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(zOrderRevMap, TCL_ONE_WORD_KEYS);
}
int isNew;
Tcl_HashEntry *hPtr = Tcl_FindHashEntry(zOrderRevMap, (char*) zOrder, &isNew);
if (!isNew) {
return Tcl_GetHashValue(hPtr);
}
/* make a handle! */
Tcl_Obj *handle = Tcl_ObjPrintf("zOrder%ld", (long) zOrder);
Tcl_SetHashValue(hPtr, handle);
Tcl_IncrRefCount(handle);
hPtr = Tcl_CreateHashEntry(zOrderMap, (char*) handle, &isNew);
Tcl_SetHashValue(hPtr, zOrder);
return handle;
}
static int
GetZOrderFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int **zOrderPtr) {
Tcl_HashTable *hPtr;
if (!zOrderMap || (hPtr = Tcl_FindHashEntry(zOrderMap, (char *) objPtr)) == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no such zOrder \"%s\"",
Tcl_GetString(objPtr)));
return TCL_ERROR;
}
*zOrderPtr = (int *) Tcl_GetHashValue(hPtr);
return TCL_OK;
}
}
有了该帮助程序代码,您就可以像这样定义自定义Critcl类型:
critcl::argtype zOrder {
if (GetZOrderFromObj(interp, @@, @A) != TCL_OK) {
return TCL_ERROR;
}
} int*
critcl::resulttype zOrder {
if (rv == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, MakeZOrderObj(rv));
return TCL_OK;
} int*
这样就可以像这样编写真正的代码。请注意,grid
被定义为(自定义)类型zOrder
,并且只能由返回zOrder
作为其结果的某些代码来制造
critcl::cproc setter {zOrder grid int value int x int y} void {
grid[xy2addr(x,y)] = value;
}
(从哈希表中删除条目并删除C数组的删除函数留作练习。)
Tcl列表变量
另一种方法是将zOrder值作为整数列表保存在Tcl变量中。这可能很好,因为它可以让您轻松地查看内部,但在其他方面也可能不太好,因为代码不受约束,无法使用正确的值,并且您可以将您的CPROC暴露在Tcl中发生的更多细节中
critcl::cproc setter {Tcl_Interp* interp object varName int value int x int y} ok {
/* Unpack the list of ints from the variable */
Tcl_Obj *listObj = Tcl_ObjGetVar2(interp, varName, NULL, TCL_LEAVE_ERR_MSG);
if (listObj == NULL)
return TCL_ERROR;
Tcl_Obj **listv; int listc;
if (Tcl_ListObjGetElements(interp, listObj, &listc, &listv) != TCL_OK)
return TCL_ERROR;
int *grid = alloca(sizeof(int) * listc);
for (int i=0; i<listc; i++)
if (Tcl_GetIntFromObj(interp, listv[i], &grid[i]) != TCL_OK)
return TCL_ERROR;
/* The core of the functionality */
grid[xy2addr(x,y)] = value;
/* Repack the list of ints from the variable; this code could be optimized in this case! */
for (int i=0; i<listc; i++)
listv[i] = Tcl_NewIntObj(grid[i]);
listObj = Tcl_NewListObj(listc, listv);
Tcl_ObjSetVar2(interp, varName, NULL, listObj, 0);
return TCL_OK;
}
critcl::cproc setter{Tcl_Interp*Interp object varName int value int x int y}确定{
/*从变量中解压缩整数列表*/
Tcl_Obj*listObj=Tcl_ObjGetVar2(interp,varName,NULL,Tcl_LEAVE_ERR_MSG);
if(listObj==NULL)
返回TCL_错误;
Tcl_Obj**listv;int listc;
if(Tcl_ListObjGetElements(interp、listObj、listc和listv)!=Tcl_确定)
返回TCL_错误;
int*grid=alloca(sizeof(int)*listc);
对于(inti=0;iYes),这需要我编写大量代码。将可变性映射到Tcl一点也不简单。
critcl::cproc setter {Tcl_Interp* interp object varName int value int x int y} ok {
/* Unpack the list of ints from the variable */
Tcl_Obj *listObj = Tcl_ObjGetVar2(interp, varName, NULL, TCL_LEAVE_ERR_MSG);
if (listObj == NULL)
return TCL_ERROR;
Tcl_Obj **listv; int listc;
if (Tcl_ListObjGetElements(interp, listObj, &listc, &listv) != TCL_OK)
return TCL_ERROR;
int *grid = alloca(sizeof(int) * listc);
for (int i=0; i<listc; i++)
if (Tcl_GetIntFromObj(interp, listv[i], &grid[i]) != TCL_OK)
return TCL_ERROR;
/* The core of the functionality */
grid[xy2addr(x,y)] = value;
/* Repack the list of ints from the variable; this code could be optimized in this case! */
for (int i=0; i<listc; i++)
listv[i] = Tcl_NewIntObj(grid[i]);
listObj = Tcl_NewListObj(listc, listv);
Tcl_ObjSetVar2(interp, varName, NULL, listObj, 0);
return TCL_OK;
}