如何在gdb中打印tcl_obj中的元素?

如何在gdb中打印tcl_obj中的元素?,gdb,tcl,Gdb,Tcl,我正在调试一个c++-tcl接口应用程序,我需要查看tcl_Objobjv的元素。 我试着做了print*(objv[1])等等,但似乎没有帮助。 有没有办法在gdb中查看Tcl\u Obj元素?从gdb中理解Tcl\u Obj*并不特别容易,因为数据结构使用了带覆盖类型的多态指针。(是的,这是一个棘手的C魔法。)然而,你肯定可以尝试一些东西。(我将假设下面的指针名为objPtr,它的类型为Tcl\u Obj*) 首先,检查objPtr->typePtr指向什么,如果有的话。NULLobjPtr

我正在调试一个c++-tcl接口应用程序,我需要查看
tcl_Obj
objv
的元素。 我试着做了
print*(objv[1])
等等,但似乎没有帮助。
有没有办法在gdb中查看
Tcl\u Obj
元素?

从gdb中理解
Tcl\u Obj*
并不特别容易,因为数据结构使用了带覆盖类型的多态指针。(是的,这是一个棘手的C魔法。)然而,你肯定可以尝试一些东西。(我将假设下面的指针名为
objPtr
,它的类型为
Tcl\u Obj*

首先,检查
objPtr->typePtr
指向什么,如果有的话。
NULL
objPtr->typePtr
意味着对象在
objPtr->bytes
字段中有一些内容,这是一个UTF-8字符串,包含
objPtr->length
字节,在
objPtr->bytes[objPtr->length]
处有
\0
个字节。一个
Tcl_Obj*
不应该让它的
objPtr->bytes
objPtr->typePtr
同时为
NULL

如果
objPtr->typePtr
不是
NULL
,它指向一个静态常量结构,该结构定义了
Tcl\u Obj*
上的基本多态类型操作(将其视为一个vtable)。您最初感兴趣的是
名称
字段;这是一个人类可读的
constchar*
字符串,它可能会对您有很大帮助。该结构中的其他内容包括如何复制对象以及如何序列化对象的定义。(
objPtr->bytes
字段实际上保存序列化。)

objPtr->typePtr
定义了对
objPtr->internalRep
的解释,这是一个C
联合体,其大小足以容纳两个通用指针(除此之外还有一些其他的东西,比如
long
double
;您还会看到
Tcl\u WideInt
,它可能是
long
,但这取决于编译器)。这是如何发生的取决于类型的实现,因此很难在这里全面介绍,但基本上,小整数的
objPtr->internalRep.longValue
字段有意义,浮点数的
objPtr->internalRep.doubleValue
字段有意义,更复杂的类型挂起结构偏离侧面

对于列表,结构实际上挂起了
objPtr->internalRep.twoPtrValue.ptr1
,实际上是一个
struct list
(它在
tclInt.h
中声明,不属于Tcl的公共API)。结构列表
中又有一个长度可变的数组,
元素
字段;不要在其中修改,否则会破坏内容。字典类似,但使用的是
struct Dict
(其中包含哈希表主题的变体)这是在
tclDictObj.c
中声明的;即使是Tcl的其余实现也看不到它们在内部是如何工作的。这是故意的

如果你想调试成一个
Tcl_Obj*
,你必须小心地进行,查看
typePtr
,在必要的地方应用相关的强制转换,并确保你使用的是保留所有符号和类型信息的Tcl调试版本

这并不能使调试整个值数组变得特别容易。最简单的方法是打印对象的字符串视图,如下所示:

print Tcl_GetString(objv[1])
请注意,这可能会触发对象的序列化(包括内存分配),因此它肯定不是完美的。(
Tcl_GetString
在必要时生成序列化-当然将其存储在
objPtr->bytes
字段中-并返回指向它的指针。这意味着返回的值肯定是UTF-8。好吧,Tcl在UTF-8上的内部变量在一些地方稍微非规范化了,这对您来说可能并不重要(现在是晚上。)


请注意,您可以使用
::Tcl::unsupported::representation
命令从Tcl 8.6(当前推荐版本)中的脚本中读取其中一些信息。从名称可以猜到,它不受支持(因为它违反了大量Tcl的基本语义模型规则)但它可以帮助您在启动连接gdb的大炮之前进行调试