奇趣技术网 收藏本站
设为主页
商务合作
首页 新闻中心 行业动态 软件新闻 安全资讯 病毒预警 漏洞发布 操作系统 Dos Win9x Win2000 WinXP Win2003 WinVista Linux Unix
数据库 DB2 Access MSSQL MySQL Oracle Sybase 编程技术 ASP PHP JSP CGI/Perl XML .Net C/C++/C# VB VC Delphi Java 汇编
安全技术 安全教学 工具介绍 漏洞利用 病毒防范 入侵检测 防火墙 安全防范 汉化破解 攻击实例 加密解密 技术论坛
中华网络安全联盟 >> 程序开发 >> 汇编 >> 汇编语言---套装软件制作(2)
程序开发
Asp
PHP
JSP
CGI/Perl
XML
.Net
C/C++/C#
Visual Basic
Visual C++
Delphi
Java
汇编语言
  • JDBC专题介绍(1)

  • 全面解析JDBC(9)

  • 全面解析JDBC(6)

  • 全面解析JDBC(5)

  • 全面解析JDBC(4)

  • 全面解析JDBC(1)

  • MySQL中修改密码及访问

  • SQL语法参考

  • 汇编语言---套装软件制作(2)
    字体:

    中华网络安全联盟    作者:佚名    来源:网络转载    时间:2006-3-21

    汇编语言---套装软件制作(2):    第三节  程式合并

        我所见过的各种组合程式虽不算多,但至少有百余个了。毛病最多的当然是缺乏完整的规划,其次则是信马游缰,一份不折不扣的流水帐!明明大门口在东边,程式硬要朝西,直到游完了大观园,天黑了,才出东门!
        这种程式我收集了一大叠,可是举来做例子,却心有余而力不足。原因无他,实在不耐烦照抄一遍,一见到就头痛!
        电脑最强的功能,便是处理繁杂重复的工作,为什么一般程式师居然存心与电脑争风吃醋呢?不说别的,光把程式输入到电脑中,就要花上几个月宝贵的光阴,真值得这样做吗?
        有一份程式,足足有四十多页,我只略作调整,便缩小到十页,处理速度则快了五倍。为什么会差这样远呢?很简单,有些人不喜欢用大脑,久而久之,习惯成自然,大脑就生了铁銹!除了等因奉此,什么都不会想了。
        要想做一个优秀的程式师,第一个条件是不能偷懒,第二个条件则要有分析观察的习惯,第三个也是最重要的,则是要有追求完美的精神。程式师要像艺术家,不论是自己的或是别人的程式,都要一而再、再而三地玩味改良。
        我曾见过一个扫地的妇人,她不管在哪里,见不得有任何脏乱。这种人才值得尊敬,这种精神是伟大的,与她的职业丝毫无关!
        程式写得不够精简,有三个原因,第一个是程式师无能,这种程式能够写完,可以运行,已算相当难得了;第二个原因是不懂技巧,硬桥硬马的干, 不知什么是效率,也不知道如何达成。自己写的程式都不见得看得懂,遑论他人的?第三则是根本缺乏敬业精神,敷衍塞责,这种人我最瞧不起。
        写程式之初,如果把任务瞭解清楚,然后分析因素,分割模组。所有类似的情况都合并到一处,再以变数代替,统一执行。这原本是份内的工作,前述的情况根本不可能发生!
        问题是发生了以后怎么办呢?我建议最好重写,如果一定要改,只好采用程式合并的技巧,浓缩一下。
        合并的目的是为了增进效率,而合并的方法则因情况不同而异,就像人生了病,必须先查出病因,否则无法下药。我试着以所知道的一些例证,简要地解说如后。

    一、过程的合并:

        要做过程的合并,首先要查明下列各点:
      1,首先找出过程类似的,全部移到一堆,如果找不到,那就没救了。
        然而,这种程式要就是太小,根本不可能有类似的情况,再不就是写作时杂乱无章,信马游缰。分明有类似的过程,但没有共通的原则,无从浓缩。当然,也可能有些程式,因工作量及处理的细节太多,以致无法浓缩。

      2,在类似的程式中,找寻相异的指令或流程,再若没有,那就是重复了,正宜合并。

      3,把相异的指令或流程用变数取代,或将不同程式之入口放在暂存器里。

      4,将各程式在应用该流程前,设好变数及使用的暂存器。

      5,合并相似的程式段,不同处应用变数取代之。

        下面举一实例,系一绘图程式之片断,兹改变原用标题,并将分散在各处若干不同之段,列述如下:
      189: MASK    PROC    NEAR
      190:        MOV    DX,3C4H
      191:        MOV    AL,2
      192:        OUT    DX,AL
      193:        MOV    DX,3C5H
      194:        MOV    AL,PCOLOR
      195:        OUT    DX,AL
      196:        RET
      197: MASK    ENDP
      …
      380:        MOV    DX,03CEH
      381:        MOV    AL,3
      382:        OUT    DX,AL
      383:        MOV    AL,18H
      384:        INC    DX
      385:        OUT    DX,AL
      386:        RET
      …
      490:        MOV    DX,3CEH
      491:        MOV    AL,3
      492:        OUT    DX,AL
      493:        MOV    DX,3CFH
      494:        MOV    AL,0H
      495:        OUT    DX,AL
      496:        RET
      …
      589: CROSS    PROC    NEAR
      590:        MOV    DX,3C4H
      591:        MOV    AL,2
      592:        OUT    DX,AL
      593:        INC    DX
      594:        MOV    AL,0FH
      595:        OUT    DX,AL
      596:        RET
      597: CROSS    ENDP
      …

        这样的段落有十多处,看来每个都略有不同,似乎不能合并。然而仔细分析,显然是程式师训练不够,把一个非常有规则的程式,安排得非常紊乱,以致到这个地步。
        我们先归纳问题,决定如何合并。第一,上述各段程式,应该统一作为子程式;第二,全部变数只有四个,其中两个是传送值,两个是输出入埠。后者有连续关系,等于只有一个。因此,在调用此子程式前,应先令DX为输出入埠,再将变数装入AX中,一次调用即可。此子程式如下:
      300: SUB:
      301:        OUT    DX,AL
      302:        INC    DX
      303:        MOV    AL,AH
      304:        OUT    DX,AL
      305:        RET
        这样简短的子程式,有无必要,端视时空的效益而定。不论怎样整理,都远比原来的要好。
        另外有种情况,更为可怕,就是在键盘输入后,用流程方式,一一比较输入码,再一一分别处理。
        比如说,为了检查游标键的左、右、上、下等八个方向的移动,以便作相应的处理,程式居然写成:
      100: PP1:    MOV    AH,0
      101:        INT    16H
      102:        CMP    AX,4800H    ;↑键
      103:        JNE    NEXT1
      104:        CALL    MOVDATA     ;SET BUFFERS
      105:        CALL    SETDLT        ;SET INCREMENT
      106: NXT01:
      107:        CALL    DOTUP
      108:        LOOP    NXT01
      109:        CALL    XORDOT        ;SET NEW DOT
      110:        CALL    XYDISP        ;DISP NEW XXX,YYY
      111:        JMP    PP1
      112: NEXT1:
      113:        CMP    AX,5000H    ;↓键
      114:        JNE    NEXT2
      115:        CALL    MOVDATA     ;SET BUFFERS
      116:        CALL    SETDLT        ;SET INCREMENT
      117: NXT02:
      118:        CALL    DOTDOWN
      119:        LOOP    NXT02
      120:        CALL    XORDOT        ;SET NEW DOT
      121:        CALL    XYDISP        ;DISP NEW XXX,YYY
      122:        JMP    PP1
      123: NEXT2:
      124:        CMP    AX,4B00H    ;←键
      125:        JNE    NEXT3
      …
        这段程式总共要检查八次,才能确定是否有游标移动以及哪个游标在移动。然后,还要一一检查其他变化,共有十八种有效码。我实在佩服这种程式师,不但有无比的耐性,还有非凡的想像力,居然能把一段极为简单平凡的程式,写得这样的精彩动人!
        如果是我,我会写得毫无趣味:
      100: PP1:    SUB    AH,AH
      101:        INT    16H
      102:        OR    AL,AL
      103:        JNZ    PP1        ;AL 非0无效
      104:        MOV    BH,AL
      105:        MOV    BL,AH
      106:        SUB    BL,47H        ;最小之字标键
      107:        JLE    PP1        ;非处理范围
      108:        SHL    BX,1
      109:        CALL    FUNC[BX]
      110:        JMP    PP1
        这是主流程,程式短,速度快,维护容易,一眼看过去,有什么错误立刻分明。
     …
     1000: FUNC    DW    NEXT02        ;↖
     1001:        DW    NEXT0        ;↑
     1002:        DW    NEXT04        ;↗
     1003:        DW    PPRET        ;无效
     1004:        DW    NEXT2        ;←
     1005:        DW    PPRET        ;无效
     1006:        DW    NEXT4        ;→
     1007:        DW    PPRET       ;无效
     1008:        DW    NEXT12        ;↙
     1009:        DW    NEXT1        ;↓
     1010:        DW    NEXT14        ;↘
     …
        因为这是子程式,加一段、减一段容易非常。
        即使是子程式,也有很大的考究,就以前段来说,在 104至110 之间,就值得三思。
      104:        CALL    MOVDATA     ;SET BUFFERS
      105:        CALL    SETDLT        ;SET INCREMENT
      106: NXT01:
      107:        CALL    DOTUP
      108:        LOOP    NXT01
      109:        CALL    XORDOT        ;SET NEW DOT
      110:        CALL    XYDISP        ;DISP NEW XXX,YYY
        首先,104 和105 会重复多次,109 及110 亦然,为什么不合并为一呢?这也是很常见的程式合并手法,两次调用合为一次,速度及空间都较为经济。
        在子程式 SETDLT 之前,先调用一次 MOVDATA,另XYDISP也是一样,首先备妥:
     3000: SETDATA:
     3001:        CALL    MOVDATA     ;假设本程式有他用
     3002: SETDLT:
     3003:          …
     …
     3100: XYDIDOT:
     3101:        CALL    XORDOT        ; 同上
     3102: XYDISP:
     3103:        …
     …
        再来设计NEXT0 的子程式:
      110: NEXT0:
      111:        CALL    SETDATA
      112: NXT01:
      113:        DOTUP  应搬至此,无需设为子程式。
      …
      120:        LOOP    NXT01
      121:        JMP    XYDIDOT     ; 如有必要,可先
                                        ; 设好参数
        这样合并一下,效果决不止高上十倍,等到真正学会了程式的技巧,写作时速度也可以提高数倍。

    二、分支的处理:

        分支是程式中不可避免的手段,使用得好,整个程式气势一贯,有行云流水之妙。
        前面的例子根本不具分支的条件,故不能算是分支不良,而是程式师观念错误。
        下面再举一例,由于分支不良,以致程式支离破碎。这是一则计算拋物线的快速程式,妙在没有用乘除法,也没有任何函数。其中有几段是这样的:
      100: BEG00:
      101:            CMP    BP,BUFY
      102:?    JLE    BE7
      103:           OR    CX,CX
      104:             JG    BE20
      105:            MOV    AX,BP
      106:?    SHL    AX,1
      107:           DEC    AX
      108:           JL    BE10
      109: BE2:
      110:             CALL    BE1
      111:            JC    BEG00
      112:          CALL    BE3
      113:            JMP    BEG00
      …
      120: BE14:
      121:?    LODSW
      122:           CMP    AH,1FH
      123:             JGE    BE141
      124:            LOOP    BE14
      125:      POP    DI
      126:          POP    CX
      127:            MOV    SI,DI
      128:              JMP    BE142
      129: BE141:
      130:            POP    DI
      131:          POP    CX
      132:          MOV    SI,DI
      …
      150: BE10:
      151:          CALL    BE1
      152:            JMP    BEG00
      153: BE20:
      154:              MOV    AX,CX
      155:?    SUB    AX,DX
      156:           SHL    AX,1
      157:             DEC    AX
      158:            JLE    BE2
      159:?    CALL    BE3
      160:           JMP    BEG00
      161: BE1:
      162:?    INC    DX
      163:           ADD    CX,DX
      164:             ADD    CX,DX
      165:            INC    CX
      166:            ADD    DI,BUFX
      167:           CMP    DI,BX
      168:             JLE    BE1RET
      169:            CALL    BE01
      170:            SUB    DI,BX
      171: BE1RET:
      172:           RET
      …
      190: BE01:
      191:?    MOV    AL,1
      192:           CMP    [SI+1],AL
      193:             JNZ    BE011
      194:            INC    BYTE PTR [SI+1]
      195:              RET
      …
      200: BE141:
      …
        全部程式并不大,不过一百多条指令,但是稍加改进,却可以省却廿多条指令,速度也会加快。重点在于106 到113 的分支错误,以致于多出BE10 BE20 BE3 BE01等段程式出来。
        照理,BE1 BE3 BE01都不该另设子程式,BE14也应改写,如此,整个程式就完全不同了。
        原来由 105为:
      105:            MOV    AX,BP     ;★无必要
      106:              SHL    AX,1     ;★无必要
      107:            DEC    AX     ;★无必要
      108:            JL    BE10
      109: BE2:
      110:             CALL    BE1     ;★合并后,无需调用
      111:            JC    BEG00     ;★另作分支
      112:           CALL    BE3     ;★也无必要调用
      113:             JMP    BEG00
        现改为:
      107: BE1:              ;原为DEC AX分支处理
      108:              INC    DX     ;原161子程式作主流程
      109:            ADD    CX,DX
      110:          ADD    CX,DX
      111:            INC    CX
      112:              ADD    DI,BUFX
      113:          CMP    DI,BX
      114:            JLE    BE11
      115: ;          CALL    BE01     ;本子程式重写如下:
      116:            CMP    BYTE PTR[SI+1],1
      117:             JNE    BE1A
      118:            INC    BYTE PTR[SI+1]
      119: BE1A:
      120:            SUB    DI,BX
      121:            JC    BEG00     ;原111
      122:            …          ;原BE3 程式
      …
        又 125条三个指令也是分支错误,白白浪费。
      120: BE14:
      121:           LODSW
      122:             CMP    AH,1FH
      123:            JGE    BE141
      124:          LOOP    BE14
      125:            POP    DI     ;★可以省略
      126:              POP    CX     ;★可以省略
      127:          MOV    SI,DI     ;★可以省略
      128:            JMP    BE142     ;★可以省略
      129: BE141:
      130:              POP    DI
      131:            POP    CX
      132:          MOV    SI,DI    ;127移到此
      133:            JNZ    BE142     ;128移到此
      134:              …

        第四节  定案包装

    一、手册:

        手册写作本来与程式写作无关,但由于一般程式师都不知道手册的重要性,往往程式写得极佳,而市场口碑却不良,以致惨遭滑铁泸之败。
        实际上,当今市场的趋势,都倾向于萤幕提示,以致于手册仅具辅助作用,帮助使用者理解各种功能的发挥而已。
        问题就出在这里,一个功能的介绍、说明,与该功能应用的发挥,完全是不同的层次。「萤幕提示」经常由程式师自行制作,而程式师对文字概念的应用及理解能力,往往并不太高明,其结果可想而知。
        手册应该有专人写作,这种人既要对文字概念应用裕如,又要充份瞭解电脑的功能。难的是,培养一个程式师,了不起三个月到半年,而一个能达意的作家,起码需要三至五年。遗憾的是,一般电脑公司没有这种眼光,以为写程式需要技术,手册则随便找人应付了事。
        手册的重要性,并非仅止于此,一个有价值的程式,一定有周详的计划,有制作的蓝图。这种计划及蓝图,经过文字概念上的整理,应该就是手册本身。换句话说,有良好规划的程式,必然是先有手册作为蓝图,再根据手册制作程式。

    二、版本:

        程式完成以后,除非一些特殊的原因,只要有实用价值,必然需要不断改进、强化。
        这一来就面临版本更新的问题,程式师在制作之初,必须事先考虑周全。不要希望一次把程式写得尽善美,完整无缺,不仅那是不可能的梦想,也是自找麻烦。
        任何一个人,即使是不世天才,也不可能经历人间所有的事件。而程式所需要适应的范围,则是动态的、随着人的知识及经验不断增长。因此,一个崭新的程式一旦问世,就成为人世间的新生事物,人的经验扩展后,新的需求即接踵而至。刚刚完成的程式,在完成的那一剎,就已成为过去式。
        所以在程式规划时,必须高瞻远瞩,考虑得越是周全,程式的生命力越是旺盛。同时,在另一方面,程式必须交到使用者手中,才有实际的价值。是以如何在周全的规划,和尽快的完成工作之间,作有效的斟酌取舍,则是个难题。
        解决的方法之一,就是利用「版本」观念,将产品分为数个时期。这样,不仅产品可以很快地交到使用者手中,而且使用者可以提供其应用经验的回馈,更有利的,是程式得以不断地增长、成熟、完善。
        有了版本的观念,还需要对版本的制作有明确的计划,每一个版本的档案维护,修订更正,都要有专人负责。否则,当已经上市的版本还需要修改,而新的版本业已开始设计,若是一个不小心,分不清档案属于哪个版本时,其后果之不堪,将非局外人所能领会的了。

    三、包装:

        此处所提的「包装」,不是商业上所谓的如何将产品美化伪装起来。而是指一个程式交到使用者手中时,应该具备哪些必备的,哪些选用的「配备程式」。
        一般大型的应用程式,经常提供很多片磁盘,要先执行一个很复杂的「初始化」程式,才能使用。如果采用组合语言制作,其目的本就是为了节省空间。空间小了,应该可以避免这种多余的手续。
        这就是包装所要考虑的问题,比如说,在我们的“聚珍整合系统”中,附有如下一些配备程式及手册:
      1,功能、操作提示或手册:
        1-1 sm.hlp:在功能提示态下,说明各功能、操作方式及注意事项。
        1-2 smvqoq.exe:聚珍整合系统操作手册阅览程式
            smvqo1.dat--smvqod.dat :操作手册资料档。
      2,smjooh.exe:繁、简体档互转程式
        smjooh.tab:繁、简体转换对照表。
      3,smjopa.exe:本系统与park文书档资料互转用。
      4,smjob5.exe:为转换其他系统生成的文书档资料用。
      5,smjib5.exe:转换dbase iii 资料档。
        这些程式及档案,都要放在同一片磁盘中,不仅为了方便省事,也可降低成本。
        在我们的经验中,这些工作说来容易,做来却大费周章。唯有在事先做好妥善的规划,最后才能省时省事,达到理想的预期效果。
        仅以萤幕提示为例,由于资料所占空间太大,就导致了极大的困难。如果事先有准备,将资料作适当的压缩,显然会省却不少麻烦。
        此外,手册的印刷,磁盘的复制,所有一切应行考虑的,都要事先想清楚。要知道,一个应用软件,其成本完全在开发及最后的包装过程,为了成功,代价是必须先付出的。
    字体:
     
    设为主页 收藏本站 联系我们 友情连接 商务合作 网友留言
    Copyright©2006-2008 中华网络安全联盟 All rights reserved.