网站模版与模板的使用,网站正在建设中html,自己建网站怎么做seo,衡水网站建设制作稍微复杂一些的程序通常需要做某种条件判断#xff0c;然后再决定程序的执行流程。当然也可以无条件跳转到程序的另一处地址开始执行。本节我们将详细介绍分支结构的程序设计方法。 针对功能较为复杂的程序#xff0c;程序开发有一套标准的流程#xff0c;我们将10.1节中的五…稍微复杂一些的程序通常需要做某种条件判断然后再决定程序的执行流程。当然也可以无条件跳转到程序的另一处地址开始执行。本节我们将详细介绍分支结构的程序设计方法。 针对功能较为复杂的程序程序开发有一套标准的流程我们将10.1节中的五个步骤进一步细化 第一步分析需求设计程序结构框架 第二步数据定义定义恰当的数据结构 第三步分析算法 第四步编写伪代码即用我们自己的语言来编写程序 第五步画流程图使用Visio、Excel或者其他绘图工具绘制算法流程和逻辑关系图 第六步编写源程序其实就是将我们的伪代码翻译成计算机语言 第七步调试程序修复程序中可能出现的BUG 第八步优化代码尝试更好的设计方案效率更高的算法逻辑更为清晰简洁明了。这一步可以使我们学到更多的东西何乐而不为呢。 在今后的学习中建议读者严格遵循这样的流程养成良好的编程习惯受益终身。 本节内容分支程序设计。
■简单分支结构汇编语言中一般利用条件测试指令和条件转移指令等实现简单的分支相当于高级语言中的if和if-else语句。
■多分支结构在分支结构中还有一种情形即需要同时做多种不同的条件判断形成多个分支语句。在高级语言中称为switch语句。示例代码t10-8.asm t10-12.asm。
10.2.1 简单分支结构 简单分支结构常见的形式有两种如流程图10-3、10-4所示。 图10-3 条件结构1 图10-4 条件结构2 汇编语言中一般利用条件测试指令和条件转移指令等实现简单的分支相当于高级语言中的if和if-else语句。接下来我们分析示例代码。
●例1排序 动手实验66实现3个无符号数由小到大排序的程序。
在理解下面示例程序的基础上自己独立编写源程序。编译完成后在debug调试器中单步跟踪调试以验证程序的正确性。
假设数据段buffer缓冲区中存储三个十进制数87、234和123。在内存中以二进制数的形式存储使用简化后的十六进制数表示为57H、EAH和7BH。
注在源程序中定义数据时我们可以直接使用十进制数、二进制数或者十六进制数编译器在编译时会将其转换为二进制数。
方法一使用3个寄存器进行比较。如图10-5所示 图10-5 3个数排序方法一 第一步分析需求3个无符号数升序排序。
第二步数据定义 buffer缓冲区存放三个自定义无符号数buffer db 87,234,123。
第三步分析算法两两比较。
第四步伪代码
assume cs:code,ds:data
数据段
;数据定义
代码段 ;给数据段赋值dsdata ;si变址指针寄存器指向buffer缓冲区 ;分别将三个无符号数依次存入al、bl、cl寄存器 ;第一次比较al、bl
如果albl需要交换xchg al,bl
如果albl不需要交换
进行第二次比较 ;第二次比较al、cl
如果alcl需要交换xchg al,cl
如果alcl不需要交换
进行第三次比较 ;第三次比较bl、cl
如果blcl需要交换xchg bl,cl
如果blcl不需要交换
;分别将al、bl、cl存入buffer缓冲区
bufferal
buffer1bl
buffer2cl
;结束
第五步画流程图如图10-6所示。 图10-6 t10-8流程图 第六步写代码
示例代码32
;程序名t10-8.asm
;功能实现3个无符号数由小到大排序
;算法3个无符号数两两比较比较3次
;程序结构分支结构
;方法一使用3个寄存器进行比较
;------------------------------------
assume cs:code,ds:data
data segment
buffer db 87,234,123
data ends
code segment
start: mov ax,data mov ds,ax ;取出三个数分别存入al、bl、cl寄存器 mov si,offset buffer mov al,[si] mov bl,[si1] mov cl,[si2] ;第一次比较 cmp al,bl jbe next1 xchg al,bl
next1: ;第二次比较 cmp al,cl jbe next2 xchg al,cl
next2: ;第三次比较 cmp bl,cl jbe next3 xchg bl,cl
next3: mov buffer,al mov buffer1,bl mov buffer2,cl
over: ; mov ax,4c00h int 21h
code ends end start 第七步调试如图10-7所示。 图10-7 调试t10-8.exe 第八步代码优化
方法二使用1个寄存器进行比较。如图10-8所示。 图10-8 3个数排序方法二
伪代码
数据定义buffer db 87,234,123
mov si,offset buffer
[SI]57H
[si1]0eah
[si2]7bh 第1和2比较
al[si]
al [si1],需要交换
al [si1],不需要交换xchg al,[si1]
[si]al 比较1和3
al,[si2]
al [si2],需要交换
al [si2],不需要交换xchg al,[si2]
[si]al 比较2和3
al[si1]
al,[si2]
al [si2],需要交换
al [si2],不需要交换xchg al,[si2]
[si1]al
结束 示例代码33
;程序名t10-9.asm
;功能实现3个无符号数由小到大排序
;算法3个无符号数两两比较比较3次
;程序结构分支结构
;方法二使用1个寄存器进行比较
;------------------------------------
assume cs:code,ds:data
data segment
buffer db 87,234,123
data ends
code segment
start: mov ax,data mov ds,ax ;取出第一个数 mov si,offset buffer mov al,[si] ;第一次比较 cmp al,[si1] jbe next1 xchg al,[si1] mov [si],al
next1: ;第二次比较 cmp al,[si2] jbe next2 xchg al,[si2] mov [si],al
next2: ;第三次比较 mov al,[si1] cmp al,[si2] jbe over xchg al,[si2] mov [si1],al
over: ; mov ax,4c00h int 21h
code ends end start
三个数排序的算法非常简单两两比较。如果按照升序排序则第一个数大于第二个数时交换位置。在使用相同算法的情况下示例代码32采用方法一需要使用三个寄存器al、bl、cl来实现。示例代码33只需要使用一个寄存器al实现。由于8086 CPU的寄存器数量有限所以建议使用方法二较为合适。 提示 为了节约篇幅从示例代码t10-8后的示例及课后练习程序不再详细描述完整的程序设计流程。请读者务必遵循七个完整的程序设计步骤独立完成。这是每一位程序员的必经之路。 ●例2一位十六进制数转换为对应的ASCII码
算法分析
如图10-7所示十六进制数0~9加上30H就是其对应的ASCII码值30H~39H。十六进制数A~F加上37H就是其对应的ASCII码值41H~46H。两种不同转换方法的判断条件是
如果该一位十六进制数小于等于9则加上30H
如果该一位十六进制数大于9则加上37H。 图10-9 一位十六进制数转换为ASCII 动手实验67写一个实现把一位十六进制数转换为对应的ASCII码的程序。
在理解下面示例程序的基础上自己独立编写源程序。编译完成后在debug调试器中单步跟踪调试以验证程序的正确性。
伪代码
1注释程序名功能
2数据定义
3alx
4比较判断0-9A-F之间
5如果是0-9al30h
6如果不是0-9则是A-F al37h
7ASCII al
8结束
示例代码34
;例2写一个实现把一位十六进制数转换为对应的ASCII码的程序
;程序名t10-10.asm
;功能十六进制数转换为ASCII码
;算法09 30HA~F 37H
;设计结构分支结构
;-----------------------------------------------------------
assume cs:code,ds:data
data segment
x db 0fh
ASCII db ?
data ends
code segment
start: mov ax,data mov ds,ax ; mov al,x add al,30h ;0~9 cmp al,39h jbe over add al,7h ;A~F
over: mov ASCII,al mov ax,4c00h int 21h
code ends end start 这个示例也可以换一种不同的方式实现比如将“jbe”改成“ja”或者是先判断x的值是否大于9然后再加30H或39H。这两种不同的逻辑留给读者独立完成。
10.2.2 多分支结构
在分支结构中还有一种情形即需要同时做多种不同的条件判断形成多个分支语句。在高级语言中称为switch语句。如图10-10所示 图10-10 多向分支结构示意图 ●例3一位16进制数所对应的ASCII码转换为16进制数
算法分析
假设ALASCII码X为转换后的16进制数分为7种情况
1AL0X-1
20AL9XAL-0
39ALAX-1
4AALFXAL-A10
5FALax-1
6aALf xAL-a10
7ALfx-1 动手实验68写一个实现把一位16进制数所对应的ASCII码转换为16进制数的程序如果没有对应数则转换为-1。
在理解下面示例程序的基础上自己独立编写源程序。编译完成后在debug调试器中单步跟踪调试以验证程序的正确性。
示例代码35
;例3写一个实现把一位16进制数所对应的ASCII码转换为16进制数的程序如果没有对应数则转换为-1
;程序名t10-11.asm
;分支结构
;功能ASCII码转换为16进制数
;-------------------------------------------------------------
assume cs:code,ds:data
data segment
x db ?
ASCII db a
data ends
code segment
start: mov ax,data mov ds,ax ; mov al,ASCII cmp al,0 jb NO cmp al,9 jbe next1 cmp al,A jb NO cmp al,F jbe next2 cmp al,a jb NO cmp al,f ja NO sub al,57h jmp LAB
next1: sub al,30h jmp LAB
next2: sub al,37h jmp LAB
LAB: mov x,al jmp over
NO: mov x,-1
over: ; mov ax,4c00h int 21h
code ends end start
代码优化 由于ASCII值可能是大写字符也可能是小写字符所以在示例代码35中同时考虑了这两种情形并且分别做了小写字符和大写字符的比较和判断。 可以考虑一种简化判断的方法在判断’A’~’F’之前先执行语句“AND ASCII,1101 1111B”将x值第5位置0不论大小写字符均统一转换为大写字符然后只需要判断大写字符即可。
请读者独立完成上述代码优化。 ●例4利用地址表实现多向分支
任何复杂的多向分支总可以分解成多个简单分支。汇编语言实现多向分支的源程序结构如下
...... cmp ah,1 ;假设x在ah寄存器中 jz yes_1 jmp not_1
yes_1: 处理语句1 ...... jmp ok
not_1: cmp ah,2 jz yes_2 jmp not_2
yes_2: 处理语句2 ...... jmp ok
not2: cmp ah,3 jnz not_3
yes_3: 处理语句3 ...... jmp not_3
not_3: cmp ah,4 jnz not_4
yes_4: 处理语句4 ......
not_4: 处理语句5 ......
ok: ......
上述代码片段中根据x的值是否为1~4使用了4个条件判断5个处理语句的结构流程图如图10-11所示。 图10-11 多分支语句流程图 谨慎 多分支语句中的JCC指令跳转的地址需要注意是否会超出跳转范围JCC指令跳转范围是-128~127。负数向前跳转正数向后跳转。 如果确实超出JCC指令跳转范围解决方案有两种
1修改该条JCC指令为相反的JCC指令。例如将ja指令改为jbe指令交换语句块位置。
2使用JMP指令接续。例
ja next1
next1:
Jmp next2
next2: 如果多分支语句过于繁琐可以考虑采用建立地址表的方案简化代码。请看下面的实验。 动手实验69假设有一个命令选择程序每次只接收一个单键命令A至H然后根据命令进行相应的处理。
算法分析
1需要根据字符A至H编写一个入口地址表又称为散转表
2需要接收键盘输入单个字符使用DOS系统的1号功能调用接收键盘输入单个字符
3需要考虑接收字符的大小写情况
4根据输入字符判断对应表项
5跳转到正确的命令地址
在理解下面示例程序的基础上自己独立编写源程序。编译完成后在debug调试器中单步跟踪调试以验证程序的正确性。 示例代码36 ;设程序每次只接收一个单键命令A至H然后根据命令进行相应的处理
;如果接受到的不是规定的命令字母则不处理。
;分析编写一个入口地址表又称为散转表。如果各处理程序均在同一代码段
;则入口地址只需要用偏移表示入口地址表宽度为‘字’。
;程序名t10-12.asm
;算法查表
;
assume cs:code,ds:data
data segment
;入口地址表
comtab dw COMA,COMB,COMC,COMD dw COME,COMF,COMG,COMH
data ends
code segment
start:
mov ah,1 int 21h ;接收键盘命令在AL中 and al,11011111b ;小写转大写 cmp al,A jb ok cmp al,H ja ok sub al,A ;把命令字母转换成序号从0开始 xor ah,ah ;清零 add ax,ax ;ax*2转换成comtab地址宽度为dw mov bx,ax ;bx基址寄存器 jmp comtab[bx] ;跳转对应的处理分支程序
ok: mov ax,4c00h int 21h
;----------------------------------------------------
COMA: ;.... JMP OK
COMB: ... JMP OK
......
COMH: ...... JMP OK code ends end start
在上述示例代码中通过入口地址表实现多分支结构入口地址由用户从键盘输入实现用户与程序之间的互动。 注意
1用户输入的ASCII字符A至H为db类型入口地址表项的数据类型为dw转换成comtab地址时需要乘以2。
2建立入口地址表时将表项与字符A至H的顺序项对应。 练习
1、请在t10-12.asm的基础上新建一个完整的实例。
2、如果条件转移超出转移范围应该如何处理
3、 写一个把字符串中的小写字母变换为对应的大写字母的程序假设字符串以0结尾。
4、写一个统计字符串长度的程序假设字符串以0结尾。
5、写一个滤去某个字符串中空格符号ASSCII码20h的程序字符串0结尾。
6、请写一个把两个字符串合并的示例程序。
7、请写一个把某个十进制数ASCII码串转换为对应的非压缩BCD和压缩BCD的示例程序。
8、请写一个把某个十进制数ASCII码串转换为BCD码对应的二进制数的示例程序。
9、请写一个把某个十六进制数转换为对应的二进制数ASCII码串的示例程序。
10、请写一个数据块拷贝的示例程序。将数据块复制到另外一个指定的地址处。 本文摘自编程达人系列教材《X86汇编语言基础教程》。