Tcl字符串函数,该函数;“闪闪发光”;破坏了我在c中定义的定制tcl类型

Tcl字符串函数,该函数;“闪闪发光”;破坏了我在c中定义的定制tcl类型,c,tcl,C,Tcl,我使用c/c++中的tcl库定义了一个定制的tcl类型。我基本上让Tcl_Obj.internalRep.otherValuePtr指向我自己的数据结构。问题是通过调用[string length myVar]或其他类似的字符串函数来解决的,这些函数执行所谓的shimmering行为,用自己的字符串结构替换我的internalRep。因此,在字符串系列tcl函数之后,myVar无法转换回!因为它是一个复杂的数据结构,无法从Tcl_Obj.bytes表示转换回来,加上类型不再是我的自定义类型。如何

我使用c/c++中的tcl库定义了一个定制的tcl类型。我基本上让
Tcl_Obj.internalRep.otherValuePtr
指向我自己的数据结构。问题是通过调用
[string length myVar]
或其他类似的字符串函数来解决的,这些函数执行所谓的shimmering行为,用自己的字符串结构替换我的internalRep。因此,在字符串系列tcl函数之后,myVar无法转换回!因为它是一个复杂的数据结构,无法从
Tcl_Obj.bytes
表示转换回来,加上类型不再是我的自定义类型。如何避免这种情况。

命令
字符串长度
将给定值的内部表示形式转换为特殊的
字符串
类型,该类型记录信息以允许快速执行许多字符串操作。除了大多数
string
命令的各种子命令外,
regexp
regsub
命令是执行此操作的主要命令(使其字符串与RE参数匹配)。如果你有一个宝贵的内在表现,你不想失去它,你应该避免这些命令;有一些操作可以避免麻烦。(Tcl主要假设内部表示不是脆弱性的,因此它们可以根据需要重新生成。使用脆弱性时要小心!)

最安全的关键操作(如需要,通过调用
updateStringProc
生成
字节
/
长度
代表,但不清除内部代表)是:

  • 替换成字符串;被替换的值将不具有内部rep,但它仍将位于原始对象中
  • eq
    ne
    表达式运算符进行比较。这与检查值是否为空字符串特别相关
请注意,还有许多其他操作会以其他方式破坏内部表示,但大多数操作不会太多地吸引人们


[编辑-评论太长]:有许多相对知名的扩展都是这样工作的(例如,TCOM和Tcl/Java都是这样做的)。你唯一能做的就是“小心”,因为这些价值观确实是脆弱的。例如,将它们放在一个数组中,然后将索引传递到数组中,因为这些索引不必是脆弱的。或者将事物作为元素保存在列表中(可能在全局变量中),并传递列表索引;这些只是简单的旧数字

< P>传统的健壮方法是在C或C++代码中放一个映射(例如,<代码> TCLH哈希表< /代码>或<代码> STD::MAP< /COD> >,并将索引变成短字符串,而不是太多意义。(我喜欢使用值类型的名称后跟一个序列号或指针的序列化,例如在
sprintf()中进行
%p
转换时可能会遇到的情况)
;打印的指针显示了更多的实现细节,如果您正在调试,它会更有帮助,通常在实践中不会产生太大的差异)。然后,从映射中删除内容将是一个显式删除操作,并且很容易提供诸如列出所有已知当前值之类的操作。这是安全的,但容易发生“泄漏”(尽管如果提供列出操作,则不会正式发生内存泄漏)。可以通过将查找缓存在
Tcl_Obj*
的内部表示中来加速它(处理删除的一种廉价方法是使用在删除某些内容时递增的序列号,并且仅当您在intrep中缓存的序列号等于主序列号时才绕过映射查找)但这通常不是什么大不了的事;只有当你在查找过程中测量到瓶颈时,才去做这类事情


但我可能只是生活在我自己的代码中的脆弱性中,并且会注意确保我永远不会破坏这些假设。问题是你对如何使用这些值不够谨慎;Tcl代码应该只是传递它们,而不是其他任何东西。此外,我也尝试过将这些东西包装在里面一个TclOO对象;它(根据TclOO的设计)对于您正在生成的很多值来说太重了,但是如果您只有少数值,并且希望使用方法将它们视为对象,那么它确实可以很好地工作(并为自动清理提供了更多选项)。

为什么要做
[string length myVar]
?Donal的回答当然告诉您在试图保留内部类型表示时应避免什么,但从我对您的问题的理解来看,您似乎有一个无法从字符串构造的内部表示。我可以理解,从字符串生成复杂内部类型的代码可能很难编写(我自己写了几篇),但我担心,如果您的自定义类型没有格式良好的字符串表示,您会给一些脚本留下一些地雷,这些地雷将很难从脚本级别进行诊断。@andymango将对此进行评论,但即使是一系列的评论也太长了,所以我将其添加到了我的答案中。@DonalFellows Doy您知道如何在Tcl_freeInternalrepProc函数中向控制台输出一些消息吗?我尝试了Tcl_Eval(interp,“put warning”)但不工作,因为它会给出运行时错误:“Tcl StackFree:不正确的freePtr(0x7f3c71559e20!=0x7f3c71559e0f)。调用顺序不正确?”