FAQ > 金融建模 > 建模问题 > 如何调试程序

Q:如何调试程序    

  • A:
    每个人有自己的编程习惯,也会形成自己的调试风格,下面简单介绍三种调试的方法,以供参考:
    将中间结果打印到屏幕

    r:=array();
      n:=0;
      stks:=array('SZ000002','SH600000');
      begt:=inttodate(20110601);
      endt:=inttodate(20110610);
      dateArr:=MarketTradeDayQk(begt,endt);
      for i:=0 to length(stks)-1 do
      begin
       stockid:=stks[i];
       setsysparam(pn_stock(),stockid);
       for j:=0 to length(dateArr)-1 do
       begin
         d:=dateArr[j];
    echo 'stockid->',stockid,'-date->',datetostr(d); 
    //打印出的数据格式为:’stockid->’SZ000001-‘date->’20110101
         setsysparam(pn_date(),d);
         r[n]:=close();
         echo tostn(r);
     //将数组以源串的形式打印到屏幕
         n++;
       end;
      end;
      return n;

    上面的这段代码,在for循环中,笔者使用了两次echo语句,第一次是将循环中的非数组的变量的值打印到屏幕上,第二次是将数组r打印到屏幕上。此处需注意,第一种使用方法,如果想将不同的变量值同时打印到屏幕上,可以通过”,”(逗号)来分割;打印数组的时候,需要使用tostn进行转换。
    在结果显示页面,“运行信息”一栏下可以看到如下的结果:

    对于数组,可以将光标放在左边的某一行(代表打印数组的某一行,目前是以源串的形式呈现,即array(7.8888,9.3332)),单击右边的“转换数据”,就会以数组的形式呈现。
    抛异常

    s:='';
      for i:=0 to 9 do
      begin
       try
       begin
         s:=s+i; //如果未加try,则本句肯定报错
       end;
       except
         echo i;
       end;
      end;
      return s;

    上面的代码中,s:=s+i;是不能执行通过的,如果不进行抛出异常的处理,那么在程序第一次运行到此处时,就会报错并停止运行。而加了try except语句后,就将无法通过的循环变量都打印到了屏幕上,这样就可以看出循环中出问题的地方。可以将上述代码复制到天软平台,看下运行结果。

    Debugreturn
    在子函数中使用debugreturn,程序返回debugreturn的结果。不同于return的地方是,return是返回到上一层,也就是该子函数被调用的地方,并从该子函数被调用处继续向下运行。
    调试运行
    调试按钮
    请注意图中红色方框标注的按钮。

    加/建断点。
    将鼠标放在某一行,单击此按钮,可以在此行加上断点,或者将已经加上的断点删除。
    调试运行。
    不同于运行按钮,单击此按钮,程序在遇到断点时会暂时停止,直到用户发出继续运行的指示。
    单步跟踪。
    在点击调试运行之后,光标会跳到当前执行完的那条语句上,等待用户的下一条指令,用户可点击单步跟踪、下一条、返回上一层调用或者是结束本次调试。现在介绍单步跟踪,当程序执行到的语句有调用到其他函数的时候,将打开这个函数,进入该被调用函数,光标会跟踪每一条调试到的语句,被调用函数中若调用了子函数,也会打开该子函数,继续跟踪调试。
    如下面范例中的断点调试,如果执行到语句 stks:=getbk('中小企业板'); ,不会打开setsysparam函数,是因为该函数是系统函数,里面的语句都是底层被封装了的语句,不显示出来。当光标执行到setsysparam(pn_date(),inttodate(20110825));或者zf:=stockzf3();时,将进入被调用的函数 inttodate或者stockzf3。而stockzf3函数中调用的子函数,也将跟踪下去。
    下一条。
    与单步跟踪不同的是,当程序执行到的语句有调用到其他函数的时候,点击下一条,不会打开断点语句中调用的子函数,而是直接执行该语句,光标也跟踪到该语句,再次点击时,则执行断点语句之后的语句了。
    如范例,当光标执行到setsysparam(pn_date(),inttodate(20110825));或者zf:=stockzf3();时,将不打开子函数进行跟踪,而是一次执行完该子函数。
    跳出当前函数,返回上一层函数。
    主要是与单步跟踪一起使用。当单步跟踪执行到子函数时,会进入子函数继续跟踪,如果用户不需要继续跟踪该子函数,可以点击该图标,跳出当前函数,返回到上一层调用了该子函数的函数中。
    如范例,如果函数跟踪到zf:=stockzf3();,继续跟踪stockzf3调用的子函数时,可以点击该图标,跳出stockzf3中调用的子函数,再点击该图标,则跳出stockzf3的跟踪,回到function42继续下一条语句跟踪。
    继续执行。
    当用户不需要跟踪整个函数,则可以点击该图标,表示不再跟踪,直接执行出结果。
    终止。
    终止调试运行。
    运行到光标处。
    范例代码

    stks:=getbk('中小企业板');
      r:=array();
      setsysparam(pn_date(),inttodate(20110825));
      for i:=0 to length(stks)-1 do
      begin
       stockid:=stks[i];
       setsysparam(pn_stock(),stockid);
       zf:=stockzf3();
       r[i]['代码']:=stockid;
       r[i]['涨幅']:=zf;
      end;
      return r;

    平台截图

    注1:图中,背景为红色所在行加了断点。
    注2:红色方框:变量显示窗口;蓝色方框:命令输入窗口;紫色方框:命令接收窗口
    注3:
    打开选中的数据。
    在变量显示窗口,可以看到数组类型的变量以<array[n]>显示,单击该按钮,可以查看该数组的详情。
    发送命令。
    在程序运行过程中,可以添加代码,例如本程序中,笔者添加了r[i]['是否交易日']:=istradeday(20110825),在右下方的方框中写入代码,单击此按钮可以将命令发送出去。那么会利用当时的变量来计算istradeday(20110825)。譬如发送命令时的系统股票为’SZ000002’,那么最后的结果,SZ000002所在行的‘是否交易日’列有值,而其他股票的该单元格为空。
    切换输入模式(Enter/Ctrl+Enter)。
    等同于“发送命令”按钮。单击此按钮可以切换发送命令的快捷键。
    远程/本地命令。
    选择了远程命令之后,在蓝色方框输入的命令才能发送到程序中执行。