分享
 
 
 

汇编指今的优化

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

最近看了朱邦复先生1990年所写的<<组合语言之艺术>>一书,收获良多.特别是书中组合语言指今优化一章写得十分精彩,虽然是以8086指今为例讲解,但有些优化方案现在也不过时,特节选如下:

(注:台湾电脑术语和大陆有些区别, 组合=汇编 程式=程序 暂存器=寄存器 回路=循环)

组合语言可以说是未经整理的、原始的电脑语言,读者们大可下一番功夫,找出其应用的规则,以发挥最高的效率。在下面,我仅就个人的经验,提供一些浅见,以供切磋研讨。

要写好程式,首先应熟记8088指令的时钟脉冲(Clock )及指令长度,一般组合语言手册中,都详列了与各指令相关的资料。「工欲善其事,必先利其器」,此之谓也。

本节所讨论的,是一般程式师容易忽略的细节,所有的例子都是从我所看过的一些程式中摘录下来的。看来没什么大了不起,可是程式的效率,受到这些小地方的影响很大。更重要的是,任何一个人,只要有「小事不做,小善不为」的习惯,我敢断言,这个人不会有什么大成就!

我最近才查到 Effective Address (EA) 的时钟值,我觉得没有必要死记。原则上,以暂存器为变数,做间接定址时为5个时钟,用直接定址则为6个;若用了两组变数,则为7至9个,三组则为11或12个。

为了便于叙述,下面以“T”表「时钟脉冲」; “B”表字元。其中

时钟脉冲T = 1 / 振荡频率

一、避免浪费速度及空间

组合语言的效率建立在指令的运用上,如果不用心体会下列指令的有效用法,组合语言的优点就难以发挥。

1, CALL ABCD

RET

这种写法,是没有用心的结果,共用了 4B,23T+20T,完全相同的功能,如:

JMP ABCD 或

JMP SHORT ABCD

却只要 2-3B,15T。

此外,上述的CALL XXXX 是调用子程式的格式,在直觉认知上,与JMP XXXX完全不同。对整体设计而言,是不可原谅的错误,侦错的时候,也很难掌握全盘的理念。 尤其是在精简程式的时候,很可能会遇到 ABCD 这个子程式完全独立,是则把这段程式直接移到 ABCD 前,不仅能节省空间,而且使程式具有连贯性,易读易用。

2, MOV AX,0

同样,这条指令要 3B,4T,如果用:

SUB AX,AX 或

XOR AX,AX

只要 2B,3T, 唯一要注意的是,后者会影响旗号,所以不要用在有旗号判断的指令前面。

在程式写作中,经常需要将暂存器或缓冲器清为0,有效的方法,是使某暂存器保持为0,以便随时应用。 因为,MOV [暂存器],[暂存器] 只要 2B,2T, 即使是清缓冲器,也比直接填0为佳。

只是,如何令暂存器保持0,则要下一番功夫了。

还有一种情况,就是在一回路中,每次都需要将 AH 清0,此时对速度要求很严,有一个指令 CBW 原为将一 个字元转换为双字元,只需 1B,2T 最有效率。可是应该注意,此时 AL 必须小于 80H,否则 AH 将成为负数。

3, ADD AX,AX

需要 2B,3T不如用:

SHL AX,1

只要2B,2T。

4, MOV AX,4

除非这时 AH 必为0,否则,应该用:

MOV AL,4

这样会少一个字元。

5, MOV AL,46H

MOV AH,0FFH

为什么不写成:

MOV AX,0FF46H

不仅省了一个字元,四个时钟,而且少打几个字母!

6, CMP CX,0

需要 4B,4T, 但若用:

OR CX,CX

完全相同的功能,但只要 2B,3T。再若用:

JCXZ XXXX

则一条指令可以替代两条,时空都省。不幸这条指令限用于CX ,对其他暂器无效。

7, SUB BX,1

这更不能原谅,4B,4T无端浪费。

DEC BX

现成的指令,1B,2T为何不用?

如果是

SUB BL,1

也应该考虑此时 BH 的情况,若可以用

DEC BX

取代,且不影响后果,亦不妨用之。

8, MOV AX,[SI]

INC SI

INC SI

这该挨骂了,一定是没有记熟指令,全部共4B,21T。

LODSW

正是为这个目的设计,却只要 1B,16T。

9, MOV CX,8

MUL CX

写这段程式之时应先养成习惯,每遇到乘、除法,就该打一下算盘。因为它们太浪费时间。8位元的要七十多个时钟,16位元则要一百多。所以若有可能,尽量设法用简单的指令取代。

SHL AX,1

SHL AX,1

SHL AX,1

原来要 5B,137T,现在只要 6B,6T。如果CX能够动用的话,则写成:

MOV CL,3

SHL AX,CL

这样更佳,而且CL之值越大越有利。用CL作为计数专 用暂存器,不仅节省空间,且因指令系在 CPU中执行,速 度也快。可是究竟快了多少? 我们做了些测试,以 SHL为例,在10MHZ 频率的机器上,作了3072 ×14270次,

所测得时间为:

指 令 :SHL AX,CL SHL AX,n

CL = 0 , 23 秒 n = 0 , 无效

CL = 1 , 27 秒 n = 1 , 14 秒

CL = 2 , 32 秒 n = 2 , 28 秒

CL = 3 , 36 秒 n = 3 , 42 秒

CL = 4 , 40 秒 n = 4 , 56 秒

CL = 5 , 44 秒 n = 5 , 71 秒

CL = 6 , 49 秒 n = 6 , 85 秒

CL = 7 , 54 秒 n = 7 , 99 秒

由此可知,用CL在大于2时即较分别执行有效。

此外,亦可利用回路做加减法,但要算算值不值得,且应注意是否有调整余数的需要。

10, MOV WORD PTR BUF1,0

MOV WORD PTR BUF2,0

MOV WORD PTR BUF3,0

MOV BYTE PTR BUF4,0

..

我见过太多这种程式,一见就无名火起! 在程式中,最好经常保留一个暂存器为0,以便应付这种情况。即使没有,也要设法使一暂存器为0,以节省时、空。

SUB AX,AX

MOV BUF1,AX

MOV BUF2,AX

MOV BUF3,AX

MOV BUF4,AL

14B,59T取代了 24B,76T,当然值得。只是,还是不 如事先有组织,考虑清楚各个缓冲器间的应用关系。以前面举的例来说,假定各缓冲器内数字,即为其实际位置关系,则可以写成:

MOV CX,3

如已知 CH 为0,则用:

MOV CL,3

SUB AX,AX

MOV DI,OFFSET BUF1

REP STOSW

STOSB

这段程式越长越占便宜,现在用10B,37T,一样划算。

11,子程式之连续调用:

CALL ABCD

CALL EFGH

如果 ABCD,EFGH 都是子程式,且调用的次数甚多,则上述调用的方式就有待商榷了。因为连续两次调用,不仅时间上不划算,空间也浪费。

若ABCD一定与EFGH连用,应将ABCD放在EFGH之前:

ABCD:

..

EFGH:

..

像这样,只要调用ABCD就够了,但这种情形多半是程式师的疏忽所致,如两个子程式必需独立使用,而上述连续调用的机会超过两次以上,则应该改为:

CALL ABCDEF

而ABCDEF则应为:

ABCDEF:

CALL ABCD

EFGH:

..

这样的写法速度不会变慢,而空间的节省则与调用的次数成正比。

12,常有些程式,当从缓冲器中取资料时,必须将暂存器高位置为0。如:

SUB AH,AH

MOV AL,BUFFER

这时应该将 BUFFER 先设为:

BUFFER DB ?,0

然后用:

MOV AX,WORD PTR BUFFER

如此,不但速度快了,空间也省了。

13,有时看来多了一个指令,但因为指令的特性,反而更为精简。如:

OR ES:[DI],BH

OR ES:[DI+1],BL

这样需要8B,32T,如果改用下面的指令:

XCHG BL,BH

OR ES:[DI],BX

XCHG BH,BL

则需7B,28T。

14,PUSH 及 POP 是保存暂存器原值的指令,都只需一个字元,但却很费时间。 PUSH 占 15T,POP 占12T,除非不得已,不可随便使用。有时由于子程式说明不清楚,程式师为了安全,又懒得检查,便把暂存器统统堆在堆栈上。尤其是在系统程式或子程式中,经常有到堆栈上堆、取的动作。实际上,花点功夫,把暂存器应用查清楚,就可以增进不少效率。 要知道,系统程式及某些子程式常常应用,有关速度的效率甚大,如果掉以轻心,就是不负责任! 保存原值的方法很多,其中较有效率的是放到一些不用的暂存器里。以我的经验,堆栈器用途最少,正好用作临时仓库。但最好的办法,还是把程式中暂存器的应用安排得合情合理,不要浪费,以免堆得太多。 还有一种方法,是在该子程式中,不用堆栈的手续,但另设一个入口,先将暂存器堆起,再来调用不用堆栈的子程式。这两个不同的入口,可以分别提供给希望快速处理,或需要保留暂存器原值者调用。

当然,更简单有效的方法,则是说明本段程式中某些暂存器将被破坏,而由调用者自行保存之。

二、程式要条理通顺

1,在比较判断的过程中,邻近值不必连比。

CMP AL,0

JE ABCD0

CMP AL,1

JE ABCD1

CMP AL,2

JE ABCD2

..

应为:

CMP AL,1

JNE ABCD0

ABCD1:

..

在标题为ABCD0 中,再作:

JA ABCD2

这种做法端视时间效益而定,似此 ABCD1之速度最快。

2,未经慎思的流程:

ADD AX,4

ABCD:

STOSW

ADD AX,4

ADD DI,2

LOOP ABCD

..

稍稍动点脑筋,就好得多了:

ABCD:

ADD AX,4

STOSW

INC DI

INC DI

LOOP ABCD

..

3,错误的处理方式:

MOV BX,SI

ABCD:

MOV BX,[BX]

OR BX,BX

JZ ABCD1

MOV SI,BX

JMP ABCD

ABCD1:

LODSW

..

上例应该写成:

MOV BX,SI

ABCD:

LODSW

OR AX,AX

JZ ABCD1

MOV SI,BX

JMP ABCD

ABCD1:

..

4,错误的流程:

TEST AL,20H

JNZ ABCD

CALL CDEF[BX]

JMP SHORT ABCD1

ABCD:

CALL CDEF[BX+2]

ABCD1:

..

应该写成:

TEST AL,20H

JZ ABCD

INC BX

INC BX

ABCD:

CALL CDEF[BX]

ABCD1:

..

5,下面是时间的损失:

PUSH DI

MOV CX,BX

REP STOSB

POP DI

PUSH,POP 很费时间,应为:

MOV CX,BX

REP STOSB

SUB DI,BX

同理,很多时候稍稍想一下,就可省下一些指令:

PUSH CX

REP MOVSB

POP CX

SUB DX,CX

为什么不干脆些?

SUB DX,CX

REP MOVSB

6,有段程式,很有规律,但却极无效率:

X1:

TEST AH,1

JZ X2

MOV BUF1,BL

X2:

TEST AH,2

JZ X3

MOV BUF2,DX ; 凡双数用DX,单数用BL

X3:

TEST AH,4

JZ X4

MOV BUF3,BL

X4:

.. ; 以下各段与上述程式相似

X8:

..

这种金玉其表的程式,最没有实用价值,改的方法应由缓冲器着手,先安排成序列,由小而大如:

BUF1 DB ?

BUF2 DW ?

BUF3 DB ?

BUF4 DW ?

..

然后,程式改为:

MOV DI,OFFSET BUF1 ; 第一个缓冲器

MOV AL,BL

MOV CX,4

X1:

SHR AH,1

JZ X2

STOSB

X2:

SHR AH,1

JZ X3

MOV [DI],DX

INC DI

INC DI

X3:

LOOP X1

7,回路最怕千回百转,不畅不顺,如:

SUB AH,AH

ABCD:

CMP AL,BL

JB ABCD1

SUB AL,BL

INC AH

JMP ABCD

ABCD1:

..

以上 ABCD1这个入口是多余的,下面就好得多:

MOV AH,-1

ABCD:

INC AH

SUB AL,BL

JA ABCD

ADD AL,BL ; 还原

..

8,当处理字码时,需要字母的序数,有这样的写法:

CMP AL,60H

JA ABCD1

SUB AL,40H ; 大写字母

ABCD:

..

ABCD1:

SUB AL,60H ; 小写字母

JMP ABCD

要知道字母码的特色在于大写为 40H 至4AH,小写为60H 至6AH ,以上程式,其实只要一个指令就可

以了:

AND AL,1FH

简单明瞭!

9,大多数的程式在程式师自己测试下很少发生错误,而一旦换一另个人执,就会发现错误百出。 其原因在于写程式者已经假定了正确的情况,当然不会以明知为错误的方式操作。可是换了一个人,没有先入为主的成见,很可能输入了「不正确」的资料,结果是问题丛生。 要知道真正的使用者,绝非设计者本人,在操作过程中,按键错误在所难免。这种错误应该在程式中事先加以检查,凡是输入资料有「正确、错误」之别者,错误性资料一定要事先加以排除。 这样做看起来似乎程式不够精简,可是正确的重要性远在精简之上。一旦发生了错误,再精简的程式也没有使 用价值。 此外,在程式中常有加、减的运算,这时也应该作正确性检查,否则会发生上述同样的问题。

三、指令应用要灵活

有一段很简单的程式,其写作的方法甚多,但是指令应用的良窳,会使得程式的效率相去天上地下,难以估计。

这段程式的用途,是要将一段资料中,英文字符大、小写相互转换。当然,转换的选择要由使用者决定,在下面程式且略去使用介面,假设已得知转换的方式。

设资料在 DS:SI中,资料长度=CX ,大写转小写时BL=0,反之,则BL=1。

我见过一种写法,简直无法原谅:

1: LOOP1:

2: CALL CHANGE

3: JC LOOP11

4: ADD AL,20H

5: JMP SHORT LOOP12

6: LOOP11:

7: SUB AL,20H

8: LOOP12:

9: MOV [SI-1],AL

10: LOOP LOOP1

11: RET

12: CHANGE:

13: LODSB

14: OR BL,BL

15: JZ CHANGS

16: CMP AL,61H

17: JB CHARET

18: CMP AL,7AH

19: JA CHARET

20: STC

21: CHARET:

22: RET

23: CHANGS:

24: CMP AL,41H

25: JB CHARET

26: CMP AL,5AH

27: JA CHARET

28: CLC

29: RET

这种程式错在把由12到29的程式写得太长,共 25B,有共用的价值,于是作为子程式调用。

试想一下,每一笔资料,都要调用一次,浪费四个字元事小,但每次要费 23+20个时钟脉冲,资料多时,不啻为天文数字。更何况这段程式写得极差,在回路中,又多浪费了几十个时钟。关于这一点,下面会继续讨论。

照上面这段程式,略加改进,写法如下:

1: CHANGE:

2: LODSB

3: OR BL,BL

4: JZ CHANGS

5: CMP AL,61H

6: JB CHARET

7: CMP AL,7AH

8: JA CHARET

9: SUB AL,20H

10: CHANG0:

11: MOV [SI-1],AL

12: CHANG1:

13: LOOP CHANGE

14: RET

15: CHANGS:

16: CMP AL,41H

17: JB CHANG1

18: CMP AL,5AH

19: JA CHANG1

20: ADD AL,20H

21: JMP CHANG1

这样的写法还是不佳,因为在回路中,用常数与暂存器比较,速度较暂存器相比为慢。应该先将需要比较的值,放在暂存器DH,DL 中,改进如次:

1: MOV AH,20H

2: MOV DX,7A61H

3: OR BL,BL

4: JZ CHANGE

5: MOV DX,5A41H

6: CHANGE:

7: LODSB

8: CMP AL,DL

9: JB CHANG1

10: CMP AL,DH

11: JA CHANG1

12: XOR AL,AH

13: MOV [SI-1],AL

14: CHANG1:

15: LOOP CHANGE

16: RET

以上这段程式,空间小,速度快,每笔资料,平均仅需不到40个时钟值,以10 MHZ计,十万笔资料,约需半秒钟!

请注意程式中所用的技巧,由2至6的分支法,就比下面这种写法为佳:

1: OR BL,BL

2: JZ CHAN1

3: MOV DX,5A41H

4: JMP SHORT CHANGE

5: CHAN1:

6: MOV DX,7A61H

7: CHANGE:

这种分支也可以由另一种技巧所取代,即预设法。事先将所需用的参数放在固定的缓冲区中,此时取用即可:

MOV DX,BWCOM ; 比较之预设值

这样程式又简单些了:

1: MOV AH,20H

2: MOV DX,BWCOM

3: CHANGE:

4: LODSB

5: CMP AL,DL

6: JB CHANG1

7: CMP AL,DH

8: JA CHANG1

9: XOR AL,AH

10: MOV [SI-1],AL

11: CHANG1:

12: LOOP CHANGE

13: RET

以上介绍为变数法技巧,即将所要比较的值,放在暂存器中。由于暂存器快速、节省空间,因此程式效率高。更重要的一点,是程式本身的弹性大,只要应用方式统一,事先把参数设妥,即可共用。

回路中的指令

回路最重要的是速度,因为本段程式,将在计数器的范围之内,连续执行下去。如果不小心浪费了几个时钟值,在回路的累积下,很可能使程式成为牛步。

要想把回路写好,一定要记清楚每个指令的执行时钟,以便选择效率最高者。同时,要知道哪些指令可以获得相同的处理效果,才能有更多的选择。

其次,在回路中,最忌讳用缓冲器,不仅占用空间大,处理速度慢,而且不能灵活运用,功能有限。另外也应极力避免常数,尽量设法经由暂存器执行,用得巧妙时,常会将整个程式的效率提高百十倍。

还有便是少用 PUSH,POP,DIV,MUL和 CALL 等浪费时钟的指令。除此之外,小心、谨慎,深思、熟虑,才是把回路写好的不二法门。

在前例中,把比较常数的指令换为比较暂存器,便是很好的证明。如果用常数,两段程式决不可能共用,时、空都无谓地浪费了。

以下再举数例,乍看这似乎有些吹毛求疵,但是仔细计算一下所浪费的时间,可能就笑不出声了。

兹假定以下回路需处理五万字元的资料,频率为 10MHZ,其情况为:

1: LOOP1:

2: LODSB

3: XOR AL,[DI]

4: STOSB

5: LOOP LOOP1

本程式计数器等于50,000,每次需

12T+14T+11T+17T=55T 个时钟脉冲

若以50,000次计,需时 47*50,000/10,000,000 秒,即约四分之一秒。

只要稍稍将指令调整一下,为:

1: LOOP1:

2: LODSW

3: XOR AX,[DI]

4: STOSW

5: LOOP LOOP1

这样计数器只要25,000次,每次

16T+18T+15T+17T=66T

则25,000次需时 66*25,000/10,000,000 秒,约六分之一秒,比前面的程式快了二分之一。

同理,在回路中加回路,而每个回路需 17T,也是很大的浪费。倘若加调用 CALL 指令,则需 23T+20T=43T,浪费得更多,读者不可不慎。

当某一段程式用得很频繁时,理应视作子程式,例如下面的 LODAX:

1: LOOP1:

2: CALL LODAX

3: LOOP LOOP1

4: RET

5: LODAX:

6: LODSW

7: XOR AX,[DI]

8: STOSW

9: RET

其实这是贪小失大,仅四个字元的程式,竟用三个字元的调用指令去交换,是绝对得不偿失的。

再如同下面的程式,颇有值得商榷之处。

1: LOOP1:

2: MOV DX,NUMBER1

3: MOV CX,NUMBER2

4: LOOP2:

5: PUSH CX

6: MOV CX,DX

7: LOOP3:

8: LODSW

9: XOR AX,[DI]

10: STOSW

11: LOOP LOOP3

12: INC DI

13: INC DI

14: POP CX

15: LOOP LOOP2

16: RET

第二个回路是多余的,这是高阶语言常用的观念,对组合语言完全不适用。

稍加改动,不损上面程式原有的条件,得到:

1: LOOP1:

2: MOV DX,NUMBER1

3: LOOP2:

4: MOV CX,NUMBER2

5: LOOP3:

6: LODSW

7: XOR AX,[DI]

8: STOSW

9: LOOP LOOP3

10: INC DI

11: INC DI

12: DEC DX

13: JNZ LOOP2

14: RET

这样回路少了一个,程式中将5,6,14,15 各条中原来为15T+2T+12T+17T=46T的时间,省为12,13,14条的

2T+16T+17T=35T。

分支处理

比较资料后,作条件分支 (Conditional Jump ),是程式中不可避免的手续。程式一长,分支距离超过 128个字元,条件分支就无法到达。当然,精简程式有时可以避免这种情形,但却不尽然。

处理条件分支的技术很多,其效率端视情况而定。最要紧的是事先规划,要比较些什么?在何种情况下?分支到哪里?做些什么工作等等。

不仅是写程式,人的各种能力,都可以由工作的方式判断出来。智慧高的人,很快就能抓住重点,再分门别类,钜细无遗的理出完整的系统。经过良好训练的专家,则能根据一套法规,逐步地整理归纳,也能推出合情合理的结果来。

老实说,电脑程式的写作技术还没有到成熟的阶段,当今所有的从业人员,都只能算是「拓荒者」,并没有真正的「专家学者」。充其量,像我个人一样,比别人机会好些,天天得以与电脑为伍,多一点经验而已。

因此,目前写程式几乎可以说没有可资遵循的法规,海阔天空,爱怎样写,就怎样写,只要能够使用,程式卖得出去,赚了大钱,就会被人视为大师。

只是这种情况维持不了多久了,初民的壁画,仅具有历史意义。今天的程式师,如果不认清现实,立刻觉醒,多致力于法规的制定,电脑将永远是个不成熟的孩子。一旦这些法规经得住考验,为未来的专家学者奠定基础,那才能真正的被视为大师。 我不讳言我们正朝着这个方向努力,但是,我却不认为做得到。因为电脑的硬体设计在今后的十年内,必然会有重大的突破,谁都难以预测会有什么结果。软体的制作观念虽然不可能有很大的改变,却难免会受到影响。只有各位年轻朋友,你们成长在电脑时代,肯多一分耕耘,必有收获!

下面,且介绍一些我对条件分支的处理技巧:

一、资料的分类

1,位元分类:

在本书第四章第五节所举的,由输入码作为输出字形的处理依据之例,就是采用位元分类的例证。

但凡以资料位元作为共同的分类讯息,而且各类皆有独特的处理方式者,皆应以其位元为顺序,用间

接定址或分支技巧,作为程式处理之手段。

2,字元分类:

每一个字元具有 256种排列组合,设若有 128种以内的分类项目,应该取双数分类,否则须用连续分类。

分类之值,立即可以用间接定址执行。但须注意,各分类的入口标题应先行定义。由于定义必须用到双字元,所以,凡采用连续分类者,其值应乘二。

3,间隔分类:

在有些情况下,原有资料不容许重新安排,而且其中若干资料已具备分类之特性,这种情况,我们称之为间隔分类。

在处理此类资料时,应该先将可以作分类处理的资料提取出来,并视为字串,定义在一缓冲区内。当须要类比时,可利用「比对字串」 (SCAS) 的指令以求得其定义位置,再作间接定址。设有

4700H,4900H,4F00H,5100H,4A2DH,4EABH

等键盘输入数据。设上述值在AX中,需要作特殊处理,分别进入COD1至COD6等子程式。

11将资料定义在缓冲器 ABC中,程式则定义在DEF:

ABC DW 4700H,4900H,4F00H,5100H,4A2DH,4E2BH

DEF DW COD1,COD2,COD3,COD4,COD5,COD6

12使DI=ABC,CX=6:

MOV DI,OFFSET ABC

MOV CX,6

13由比对字串后,判断是否AX中有上述之值,如有,则用间接定址的方式执行之。

REPNZ SCASW ; 比对六组字串

JCXZ NOTHING ; 没有所比之字串

SUB DI,OFFSET ABC+2 ; 得到比对位置值

CALL CS:DEF[DI] ; 或作JMP

上述之DEF 如果放在DG段中,还可以节省一字元,并可加快速度:

CALL DEF[DI]

二、程式的结构

若在程式规划之初,未先做好准备工作,临时想用前述的方法,并非绝不可能。但是,东添一点,西补一段,这种程式不仅会导致测试的麻烦,更可能影响未来的维护和调整。

因此,每当瞭解了工作任务后,需要作间接定址的部份,最好能集中在一个模组内。万一性质不同必须分割,也应该将间接定址的程式,置放在模组的起头处。

这样做的好处很多,一方面便于扩充功能,每次增加定址因素时,不必在程式中寻来找去,立刻可以安排妥当。其次,这种定址的需求,必然与整体功能有关,而且定义表相当于一个目录,把纲领放在前面,按图索骥,一目瞭然。更重要的,是可以表现出程式结构的层次,层次处理是网状流程中最难以掌握的一环,不可不慎。

还有,就是各子程式的标题安排,其位置的先后应以功能的集中性为准。这样做的好处是,如果有可以共用的程式段,很容易就可合并为一,节省空间。

三、次序与条件「真」「假」

条件分支的「时钟数」有二个可能,条件符合时,执行分支为 16T,不符合则为 4T ,且继续下一指令。两者相差有四倍之多,我们正该利用这一特点,速度重要的条件,都应该设为主流程,否则为分流程。 尤其是在需要高速的回路中,分支处理得好坏,效率相去甚远。这种分支需要平时多加小心,培养出良好的习惯。

CDEF:

CMP AL,'?'

JZ ABCD ; 各比较符号中,'?' 者最少

LOOP CDEF ; NZ条件仅需4T速度较快

ABCD:

..

四、JMP 与 JMP SHORT

当程式师专心写作或侦错之时,常无法瞻前顾后。然而侦错完毕程式无误时,最好彻底检查一下所有的JMP 指令,经常会大有斩获!

因JMP 需要三字元,而JMP SHORT 只要两个,其条件是所跳越的位址不能超过128 字元。

在程式编译时,若向上JMP 的距离在 128字元以内,编译器会自动译为两字元。往下则不然,如在128 字元内,会再多加一个 NOP指令,不仅浪费一字元且多了两个时钟。

因此,细心检查一下,凡是向下跳,在128 字元以内,皆应改为JMP SHORT 才是。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有