- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在编写一个创建新命令的 C DLL:
Tcl_CreateObjCommand( interp, "work_on_dict", (Tcl_ObjCmdProc *)work_on_dict_cmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL );
命令的实现是:
int work_on_dict_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] )
{
Tcl_Obj *dReturn = Tcl_DuplicateObj( objv[1] ); <------------------- duplicate
Tcl_DictObjPut( interp, dReturn, Tcl_NewStringObj("key2", -1), Tcl_NewIntObj(2) );
Tcl_SetObjResult( interp, dReturn );
return TCL_OK;
}
调用它的 Tcl 代码如下所示:
set dDict [dict create]
dict set dDict "key1" 1
set dDict [work_on_dict $dDict] <------------------- assign back
puts "[dict get $dDict "key1"] [dict get $dDict "key2"]"
在更改 C 代码中的字典之前,我必须复制它。否则我会收到“使用共享对象调用”错误。所以我必须在 Tcl 代码中将返回的字典分配回原来的字典。
我想知道是否有更聪明的方法,允许 C 代码直接在原始字典上工作。类似于 Tcl 中的“work_on_dict dDict”以及在 C 代码中取消引用参数。
我尝试了很多东西,但没有得出结论,如果这毕竟是可能的。
如果有人能给我提示,我会很高兴,谢谢。
这是解决方案 - 来自 Donal 的回答:
C 代码:
请注意,您应该添加错误检查,可能将搜索范围限制为 TCL_NAMESPACE_ONLY 并调用 Tcl_ObjSetVar2 以获取正确的跟踪作为 Donal 状态。
int work_on_dict_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] )
{
Tcl_Obj *dReturn = Tcl_ObjGetVar2( interp, objv[1], NULL, 0 );
Tcl_DictObjPut( interp, dReturn, Tcl_NewStringObj("key2", -1), Tcl_NewIntObj(2) );
Tcl_SetObjResult( interp, dReturn );
return TCL_OK;
}
Tcl:
set dDict [dict create]
dict set dDict "key1" 1
work_on_dict dDict
puts "[dict get $dDict "key1"] [dict get $dDict "key2"]"
最佳答案
在您调用命令的方式中,您至少有两个对字典的引用,一个来自保存它的变量,另一个来自调用期间的参数堆栈。当然,可能还有其他人。
解决问题的标准方法是让 Tcl_DuplicateObj(dictPtr)
调用以 Tcl_IsShared(dictPtr)
是否返回 true 为条件。这样您就可以像这样调用您的代码以提高工作效率:
set dDict [work_on_dict $dDict[set dDict {}]]
是的,那很丑。如果我们使用这个使用“知名”组合器的旧版本,会更容易理解:K。
proc K {x y} {return $x}
set dDict [work_on_dict [K $dDict [set dDict anyOldConstantValue]]]
与 K
等的扭曲最终只将引用转移到参数堆栈,删除变量中保存的引用,这样你的命令就会被有效地调用。看起来很疯狂的惊人/恐怖版本实际上也是这样做的,但纯粹是字节码:
% tcl::unsupported::disassemble script {set dDict [work_on_dict $dDict[set dDict {}]]}
ByteCode 0x0x1008aee10, refCt 1, epoch 15, interp 0x0x100829a10 (epoch 15)
Source "set dDict [work_on_dict $dDict[set dDict {}]]"
Cmds 3, src 45, inst 27, litObjs 3, aux 0, stkDepth 5, code/src 0.00
Commands 3:
1: pc 0-25, src 0-44 2: pc 2-24, src 11-43
3: pc 7-20, src 31-42
Command 1: "set dDict [work_on_dict $dDict[set dDict {}]]"
(0) push1 0 # "dDict"
Command 2: "work_on_dict $dDict[set dDict {}]"
(2) push1 1 # "work_on_dict"
(4) push1 0 # "dDict"
(6) loadStk
Command 3: "set dDict {}"
(7) startCommand +14 1 # next cmd at pc 21
(16) push1 0 # "dDict"
(18) push1 2 # ""
(20) storeStk
(21) concat1 2
(23) invokeStk1 2
(25) storeStk
(26) done
concat1
操作码有一个优化,这意味着如果第二个字符串是空字符串文字,它什么都不做。
通常进行字典(或列表)修改的命令通常采用包含字典的变量的名称。 (例如,这就是 dict set
和 dict unset
所做的。)因为从 C 端的变量读取(可能使用 Tcl_ObjGetVar2
)不会' 更改引用计数,如果该值仅保存在变量中,您将能够直接更新它。您还应该在写入后调用 Tcl_ObjSetVar2
,以便触发变量上的任何跟踪。
这样,您可以将命令更改为这样调用:
work_on_dict dDict
注意那里没有$
;您传递的是变量的名称,而不是内容。
关于c - TclLib C DLL,避免 Tcl_DuplicateObj,调用时出现共享对象错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26384619/
我正在编写一个创建新命令的 C DLL: Tcl_CreateObjCommand( interp, "work_on_dict", (Tcl_ObjCmdProc *)work_on_dict_cm
我已阅读 Tcl_SetHashValue [1] 的文档,但我有一个问题。 TclLib 函数 Tcl_SetHashValue 是否允许在 #define NULL 0 的情况下值为 NULL?
我是一名优秀的程序员,十分优秀!