在 dbx 中,可以执行两种类型的数据检查:
对数据求值 (print)。抽查表达式的值
显示数据 (display)。监视每次程序停止时表达式的值
本章由以下部分组成:
本节讨论如何使用 dbx 对变量和表达式求值。
如果不确定 dbx 对其求值的变量,可使用 which 命令查看 dbx 使用的全限定名。
要查看在其中定义变量名的其他函数和文件,请使用 whereis 命令。
有关这些命令的信息,请参见which 命令和whereis 命令。
要对当前函数的作用域之外的变量进行求值或监视时,请执行下列操作之一:
限定函数名。请参见使用作用域转换操作符限定符号。例如:
(dbx) print ‘item |
通过更改当前函数来访问该函数。请参见导航到代码。
表达式应遵循当前语言的语法,但 dbx 中引入以用来处理作用域和数组的元语法除外。
print expression |
可以使用 print 命令对 Java 代码中的表达式、局部变量或参数求值。
有关更多信息,请参见print 命令。
dbx 支持 C++ dynamic_cast 和 typeid 操作符。使用这两个操作符求表达式的值时, dbx 会调用由编译器提供的一些 rtti 函数。如果源代码没有明确使用这些操作符,编译器便不会生成这些函数,因此 dbx 将无法求表达式的值。
在 C++ 中,对象指针有两种类型:静态类型(在源代码中定义)和动态类型(对象进行类型转换之前的状况)。dbx 有时可以提供有关对象的动态类型的信息。
通常情况下,如果对象有虚拟函数表(即 vtable),dbx 便可使用 vtable 中的信息正确地确定对象的类型。
可以在 print 命令、display 命令或 watch 命令中使用 -r(递归)选项。此时 dbx 将显示通过类直接定义的所有数据成员以及从基类继承的所有数据成员。
在这些命令中还可使用 -d 或 +d 选项,用来切换 dbx 环境变量 output_derived_type 的缺省行为。
如果在没有运行进程时使用 -d 标志或将 dbx 环境变量 output_dynamic_type 设置为 on,将生成 "program is not active" 错误消息,因为在调试核心转储文件时没有进程便无法访问动态信息。如果尝试通过虚拟继承来查找动态类型,将生成 "illegal cast on class pointers" 的错误消息。(在 C++ 中,从虚拟基类转换到派生类是非法的。)
C++ 允许使用未命名的参数来定义函数。例如:
void tester(int) { }; main(int, char **) { tester(1); }; |
虽然未命名参数不能在程序中的其他地方使用,但是编译器会按某种格式对未命名参数进行编码,让您可以对其求值。该格式如下(这里,编译器为 %n 赋整数值):
_ARG%n |
要获取由编译器分配的函数名称,请键入 whatis 命令,并用函数名称作为其目标。
(dbx) whatis tester void tester(int _ARG1); (dbx) whatis main int main(int _ARG1, char **_ARG2); |
有关更多信息,请参见whatis 命令。
要对未命名的函数参数求值(或显示未命名的函数参数),请键入:
(dbx) print _ARG1 _ARG1 = 4 |
非关联化指针时,请查看该指针指向的容器的内容。
非关联化指针时,dbx 会在命令窗格中显示求值;在下面的示例中,即由 t 指向的值:
(dbx) print *t *t = { a = 4 } |
监视每次程序停止时表达式的值是一种了解特定表达式或变量的变化情况和变化时间的有效方法。display 命令可指示 dbx 监视一个或多个指定的表达式或变量。监视会一直持续进行,直至使用 undisplay 命令将其关闭为止。watch 命令用于在每个停止点处以相应点的当前作用域对表达式求值并进行打印。
display expression, ... |
一次可以监视不止一个变量。如果 display 命令不带选项,则将打印显示的所有表达式的列表。
有关更多信息,请参见display 命令。
要监视每个停止点处表达式 expression 的值,请键入:
watch expression, ... |
有关更多信息,请参见watch 命令。
dbx 会一直显示监视的变量值,直至使用 undisplay 命令关闭显示为止。可以关闭指定的表达式的显示,也可以关闭当前监视的所有表达式的显示。
undisplay expression |
undisplay 0 |
有关更多信息,请参见undisplay 命令。
assign variable = expression |
以下是 Fortran 数组示例:
integer*4 arr(1:6, 4:7) |
要对数组求值,可使用 print 命令。例如:
(dbx) print arr(2,4) |
使用 dbx print 命令可以对大型数组的一部分求值。数组求值包括:
进行数组分片时,可以使用跨距,也可以不使用跨距。(缺省跨距值为 1,即表示打印每个元素。)
C、C++ 和 Fortran 语言中的 print、display 和 watch 命令支持数组分片。
对于数组的每个维度,对数组分片的完整 print 命令语法如下:
print array-expression [first-expression .. last-expression : stride-expression] |
其中:
求值结果应为数组或指针类型的表达式。
要打印的第一个元素。缺省值为 0。
要打印的最后一个元素。缺省值为数组上界。
跨距长度(跳过的元素个数为 stride-expression-1)。缺省值为 1。
第一个表达式、最后一个表达式和跨距表达式都是可选表达式,它们的求值结果应为整数。
例如:
(dbx) print arr[2..4] arr[2..4] = [2] = 2 [3] = 3 [4] = 4 (dbx) print arr[..2] arr[0..2] = [0] = 0 [1] = 1 [2] = 2 (dbx) print arr[2..6:2] arr[2..6:2] = [2] = 2 [4] = 4 [6] = 6 |
对于数组的每个维度, 对数组分片的完整 print 命令语法如下:
print array-expression [first-expression : last-expression : stride-expression] |
其中:
求值结果应为数组类型的表达式。
某个范围内的第一个元素,也是要打印的第一个元素。缺省值为数组下界。
某个范围内的最后一个元素,但如果跨距不等于 1,则可能不是要打印的最后一个元素。缺省值为数组上界。
跨距长度。缺省值为 1。
第一个表达式、最后一个表达式和跨距表达式都是可选表达式,它们的求值结果应为整数。对于 n 维数组片,请用逗号分隔各片的定义。
例如:
(dbx) print arr(2:6) arr(2:6) = (2) 2 (3) 3 (4) 4 (5) 5 (6) 6 (dbx) print arr(2:6:2) arr(2:6:2) = (2) 2 (4) 4 (6) 6 |
要指定行和列,请键入:
demo% f95 -g -silent ShoSli.f demo% dbx a.out Reading symbolic information for a.out (dbx) list 1,12 1 INTEGER*4 a(3,4), col, row 2 DO row = 1,3 3 DO col = 1,4 4 a(row,col) = (row*10) + col 5 END DO 6 END DO 7 DO row = 1, 3 8 WRITE(*,’(4I3)’) (a(row,col),col=1,4) 9 END DO 10 END (dbx) stop at 7 (1) stop at "ShoSli.f":7 (dbx) run Running: a.out stopped in MAIN at line 7 in file "ShoSli.f" 7 DO row = 1, 3 |
要打印第 3 行,请键入:
(dbx) print a(3:3,1:4) ’ShoSli’MAIN’a(3:3, 1:4) = (3,1) 31 (3,2) 32 (3,3) 33 (3,4) 34 (dbx) |
要打印第 4 列,请键入:
(dbx) print a(1:3,4:4) ’ShoSli’MAIN’a(1:3, 1:4) = (1,4) 14 (2,4) 24 (3,4) 34 (dbx) |
以下是一个二维矩形 C++ 数组片示例(省略了缺省跨距 1)。
print arr(201:203, 101:105) |
此命令打印大型数组的一部分元素。请注意,该命令省略了 stride-expression,使用的是缺省跨距值 1。
如上所示,前两个表达式 (201:203) 指定该二维数组的第一个维度中的数组片(三行一列)。数组片从第 201 行开始,到第 203 行结束。第二组表达式(以逗号与第一组表达式分开)用于定义第二个维度的数组片。该数组片从第 101 列开始,到第 105 列结束。
指示 print 跨越数组片时,dbx 只对该数组片中的某些元素求值,而跳过对其求值的各个元素之间一定数量的元素。
数组分片语法中的第三个表达式 stride-expression 指定跨距长度。stride-expression 值指定要打印的元素。缺省跨距值为 1,即: 对指定数组片中的所有元素求值。
以下数组与上一数组片示例使用的数组相同。这一次,print 命令中,第二个维度中数组片的跨距为 2。
print arr(201:203, 101:105:2) |
如图所示,使用跨距 2 时,将打印所有第二个元素,而跳过所有其他元素。
对于省略的表达式,打印时取与数组的声明大小相等的缺省值。以下是如何使用简化语法的示例。
对于一维数组,请使用下列命令:
使用缺省边界打印整个数组。
使用缺省边界和缺省跨距 1 打印整个数组。
使用跨距 stride-expression 打印整个数组。
对于二维数组,可使用以下命令打印整个数组。
print arr |
要打印二维数组中第二个维度的所有第三个元素,请键入:
print arr (:,::3) |
美化打印让程序可通过函数调用以自己的方式呈现表达式值。如果在 print 命令、rprint 命令、 display 命令或 watch 命令中指定 -p 选项,则 dbx 会搜索格式为 const chars *db_pretty_print(const T *, int flags, const char *fmt) 的函数并调用它,从而替换返回值以便打印或显示。
以该函数的 flags 参数传递的值是按位操作值或以下所列之一:
FVERBOSE |
0x1 |
目前尚未实现,始终设置 |
FDYNAMIC |
0x2 |
-d |
FRECURSE |
0x4 |
-r |
FFORMAT |
0x8 |
-f (如果设置,fmt 是格式部分) |
FLITERAL |
0x10 |
-l |
db_pretty_print() 函数可以是静态成员函数,也可以是独立函数。
如果 dbx 环境变量 output_pretty_print 设置为 on,-p 会传递到 print 命令、 rprint 命令或 display 命令中作为缺省选项。可使用 +p 来覆盖此行为。
另外需要考虑以下各项:
在 7.6 版之前,美化打印基于 prettyprint 的 ksh 实现。虽然此 ksh 函数(及其预定义别名 pp)仍然存在, 大部分语义已在 dbx 重新实现,结果如下:
对于 IDE,可以对监视、局部变量和提示框求值应用美化打印。
在 print 命令、display 命令和 watch 命令中,-p 选项表示使用本地路由。
提高了可伸缩性,尤其是现在可频繁调用美化打印,特别是用于监视和局部变量的情况下。
可以更好地从表达式中得到地址。
具有更好的错误恢复功能。
一般来讲,对于 const/volatile 非限定类型,db_pretty_print(int *, ...() 和 db_pretty_print(const int *, ...)() 等函数视为不同函数。dbx 的重载解析方法是识别性但非强制性的:
识别性。如果定义了声明为 int 和 const int 的变量,各变量会传送到适当的函数中。
非强制性。如果只定义了一个 int 或 const int 变量,它们会传送到两种函数中。此行为不是特定于美化打印的,而是适用于任何调用。
以下情况下会调用美化打印函数:
执行 print -p 或当 dbx 环境变量 output_pretty_print 设置为 on 时。
执行 display -p 或当 dbx 环境变量 output_pretty_print 设置为 on 时。
执行 watch -p 或当 dbx 环境变量 output_pretty_print 设置为 on 时。
使用提示框求值,当 dbx 环境变量 output_pretty_print 设置为 on 时。
使用局部变量,当 dbx 环境变量 output_pretty_print 设置为 on 时。
以下情况下不会调用美化打印函数:
使用 $[]。原因是 $[] 专门用于脚本中,且需要是可以预测的。
执行 dump 命令。dump 与 where 命令使用相同的简化格式,可能会在将来转为使用美化打印。IDE 的 "Local Variables" 窗口不存在这一限制。
对于嵌套值,无法进行美化打印,因为 dbx 没有用于计算嵌套字段的地址的基础结构。
必须使用 -g 选项编译 db_pretty_print(),因为 dbx 需要能够访问参数签名。
允许 db_pretty_print() 函数返回 NULL。
传递给 db_pretty_print() 函数的主指针可以确保是非 NULL 的,但它仍可能指向初始化不当的对象。
缺省情况下,dbx 环境变量 output_pretty_print_fallback 设置为 on,这表示如果美化打印失败,dbx 将回退为采用常规格式。如果该环境变量设置为 off,则当美化打印失败时,dbx 将发出错误消息。
如果出现以下可检测并可恢复的情况之一,美化打印可能失败:
未找到美化打印函数。
无法获取要美化打印的表达式的地址。
函数调用未立即返回,这可能表示由于遇到错误对象时美化打印函数不够强健而导致出现段错误。它也可能表示遇到一个用户断点。
美化打印函数返回了 NULL。
美化打印函数返回了 dbx 无法间接使用的指针。
正在调试核心转储文件。
所有情况(函数调用未立即返回除外)下,上述失败都不会有任何提示,dbx 会回退为采用常规格式。但如果环境变量 output_pretty_print_fallback 设置为 off,当美化打印失败时,dbx 将发出错误消息。
但是,如果使用 print -p 命令,而不将 dbx 环境变量 output_pretty_print 设置为 on,dbx 会在中断的函数中停止,让您可以诊断失败的原因。然后可使用 pop-c 命令来清除此调用。
db_pretty_print() 函数需要通过其第一个参数的类型来消除岐义。在 C 中,可通过将函数写为静态文件来重载它们。