首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

功能丰富的 Perl:轻松调试 Perl -1

功能丰富的 Perl:轻松调试 Perl -1

正如死亡和税收一样,错误是不可避免的。然而,以下内容应该可以帮助您避免这些错误。某些示例需要 Perl 5.6.0 或至少是 5.005 的版本。如果要尝试 Emacs 示例,可能还需要安装 Emacs 编辑器。
错误所带来的麻烦软件开发人员通常都低估了软件测试的重要性。这一现象的根本原因很简单:处理错误很困难!因为错误往往暴露了代码的根本缺陷,所以有时候开发人员甚至会为了几个错误而从头开始重新编写项目的主要部分。
我认为,调试如此重要,以至于至少要为其分配整个项目 30% 的时间。额外的调试时间将导致更好的产品。另一方面,如果为了更快地推出软件而缩短调试时间,那么在软件生成后,您将花上双份的时间来修复那些稍后暴露出的问题。
有三种基本类型的错误:编码错误、文档错误和需求错误。需求错误通常由于需求不严密或缺少需求而导致。文档错误存在于手册或联机帮助中。编码错误是由程序员在实现需求时的错误而引起的。不幸的是,需求错误和文档错误不在本文范围之内,因此,我们只好只讨论如何“检测”、“解决”和 “修复”编码错误了。
调试术语断点:程序中的一个位置,程序将在这里停止执行,并且控制将返回到调试器。        
调试器(调试员):1) 控制调试进程并带有为支持该进程而特别编写的设施的程序;2) 执行调试的人员。        
执行堆栈:到目前为止在程序执行期间输入的函数列表。例如,如果主程序调用函数 A,然后函数 A 调用函数 B,则执行堆栈是:主程序 -> A -> B。        
单步进入:通过          进入当前选定的代码行继续执行步骤。如果当前代码行包含函数,则“单步进入”将进入该函数。        
单步跳过:跳过当前选定的代码行继续执行。将不考虑代码行的内容而无条件地执行,并且一旦完成,控制即返回到调试器。        
观察:变量值发生更改时自动触发的操作。        
有关调试方面的其它信息源,请          参阅下面的 一节。

调试的基本概念我们已经将编码错误定义成程序员在实现需求时产生的错误。编码错误会导致不正确的程序行为(偏离需求的行为)。因此,程序员在编写或调试程序之前首先应该知道的是程序需求。
调试与狩猎没什么不同。第一步是检测错误(通过观察错误的行为并确认其模式)。在这个阶段,错误只是一些症状。
第二步是解决错误。因为必须要在源代码中消除错误,所以,应该有一个精通程序的人来检查错误,并知道这些错误的根本原因。如果代码理解起来更容易,并且现在的代码没有比当初错误版本中的代码更多,则您可能做对了。
第三步,也是最后一步,是修复错误(请注意“修复”与“解决”是有区别的)。调试程序将源代码更改放入“现场”的生产过程,然后检查它是否正确。如果代码不正确,则表明您没有解决错误,甚至更糟糕的是,可能还引入了新的错误。既然解决错误的目的不应该是引入新错误,请确保在解决错误之后修复每个错误。
要确保迅速找到错误并很好地理解它们,您应该对调试过程中程序使用模块和类在每个主要分支处的操作非常清楚。当然,这要求您对编写代码所用的语言(在我们的示例中是 Perl)有深入的了解。因为存在所有这些需求,所以很难找到好的软件测试人员。
Perl 调试器Perl 程序员的第一个资源是 Perl 所带的调试器。如您所见,着手使用该调试器是非常容易的。
用调试器运行一个脚本
1
perl -d program.pl




Perl 调试器自带帮助('h' 或 'h h' 分别用于详细和简短的帮助屏幕)。perldoc perldebug 页面(在命令提示窗口输入 "perldoc perldebug")有更完整的 Perl 调试器描述。
现在,让我们从一个有错误的程序着手,看一下 Perl 调试器是如何工作的。首先,它将尝试打印一个文件的前 20 行。
buggy.pl
1
2
3
4
5
6
7
#!/usr/bin/perl -w
use strict;
foreach (0..20)
{
  my $line = <>;
  print "$_ : $line";
}




当它独自运行时,buggy.pl 将失败,并给出消息:"Use of uninitialized value in concatenation (.) at ./buggy.pl line 8, <> line 9."。更神秘的是,它还自己在一行上打印 "9:" 并等待用户输入。
那意味着什么?如果调用了 Perl 调试器,您可能已经找到问题所在了。
首先,让我们证实这个错误是可以重复的。我们将在第 8 行设置一个操作来打印发生错误的 $line,然后再运行程序。
buggy.pl 调试器命令
1
2
3
4
5
6
7
8
9
> perl -d ./buggy.pl buggy.pl
Default die handler restored.
Loading DB routines from perl5db.pl version 1.07
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main:./buggy.pl:5):   foreach (0..20)
main:./buggy.pl:6):   {
  DB<1> use Data:umper
  DB<2> a 8 print 'The line variable is now ', Dumper $line




装入了 Data:umper 模块,以便自动操作可以使用一种美观的输出格式。自动操作被设置成每次到达第 8 行时都执行打印语句。现在,让我们演示一下。
buggy.pl 调试器命令,第 2 部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
DB<3> c
The line variable is now $VAR1 = '#!/usr/bin/perl -w
';
0 : #!/usr/bin/perl -w
The line variable is now $VAR1 = '
';
1 :
The line variable is now $VAR1 = 'use strict;
';
2 : use strict;
The line variable is now $VAR1 = '
';
3 :
The line variable is now $VAR1 = 'foreach (0..20)
';
4 : foreach (0..20)
The line variable is now $VAR1 = '{
';
5 : {
The line variable is now $VAR1 = ' my $line = <>;
';
6 :  my $line = <>;
The line variable is now $VAR1 = ' print "$_ : $line";
';
7 :  print "$_ : $line";
The line variable is now $VAR1 = '}
';
8 : }
The line variable is now $VAR1 = undef;
Use of uninitialized value in concatenation (.) at ./buggy.pl line 8, <> line 9.
9 :




现在很清楚,没有定义行变量时就会出问题。而且,程序等待更多的输入。再按 11 次回车键产生了以下输出:
buggy.pl 调试器命令,第 3 部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
The line variable is now $VAR1 = '
';
10 :
The line variable is now $VAR1 = '
';
11 :
The line variable is now $VAR1 = '
';
12 :
The line variable is now $VAR1 = '
';
13 :
The line variable is now $VAR1 = '
';
14 :
The line variable is now $VAR1 = '
';
15 :
The line variable is now $VAR1 = '
';
16 :
The line variable is now $VAR1 = '
';
17 :
The line variable is now $VAR1 = '
';
18 :
The line variable is now $VAR1 = '
';
19 :
The line variable is now $VAR1 = '
';
20 :
Debugged program terminated.  Use q to quit or R to restart,
  use O inhibit_exit to avoid stopping after program termination,
  h q, h R or h O to get additional info.  
  DB<3>




到现在为止已经很清楚了,由于即使在不存在行的情况下,程序仍无条件地等待 20 行的输入,所以程序会出错。修复就是要在从 <> filehandle 读取 $line 之后测试它:
buggy.pl fixed
1
2
3
4
5
6
7
8
#!/usr/bin/perl -w
use strict;
foreach (0..20)
{
my $line = <>;
last unless defined $line;     # exit loop if $line is not defined
print "$_ : $line";
}




如您所见,修复过的程序在所有情况下都可以正确工作!
返回列表