【新书推荐】10.2 分支程序设计

稍微复杂一些的程序通常需要做某种条件判断,然后再决定程序的执行流程。当然也可以无条件跳转到程序的另一处地址开始执行。本节我们将详细介绍分支结构的程序设计方法。

         针对功能较为复杂的程序,程序开发有一套标准的流程,我们将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

数据段

;数据定义

代码段

         ;给数据段赋值ds=data

         ;si变址指针寄存器指向buffer缓冲区

         ;分别将三个无符号数依次存入al、bl、cl寄存器

         ;第一次比较al、bl

如果al>bl,需要交换,xchg al,bl

如果al<=bl,不需要交换

进行第二次比较

         ;第二次比较al、cl

如果al>cl,需要交换,xchg al,cl

如果al<=cl,不需要交换

进行第三次比较

         ;第三次比较bl、cl

如果bl>cl,需要交换,xchg bl,cl

如果bl<=cl,不需要交换

;分别将al、bl、cl存入buffer缓冲区

buffer=al

buffer+1=bl

buffer+2=cl

;结束                                                                                                                                          

第五步:画流程图,如图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,[si+1]

         mov cl,[si+2]

         ;第一次比较                                                          

         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 buffer+1,bl

         mov buffer+2,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                    

[si+1]=0eah                        

[si+2]=7bh                          

                           

第1和2比较                            

al=[si]                         

al > [si+1],需要交换                           

al <= [si+1],不需要交换,xchg al,[si+1]                   

[si]=al                         

比较1和3                        

al,[si+2]                      

al > [si+2],需要交换                           

al <= [si+2],不需要交换,xchg al,[si+2]                   

[si]=al                         

比较2和3                                 

al=[si+1]                     

al,[si+2]                      

al > [si+2],需要交换                           

al <=  [si+2],不需要交换,xchg al,[si+2]                        

[si+1]=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,[si+1]

         jbe next1

         xchg al,[si+1]

         mov [si],al

next1:

         ;第二次比较

         cmp al,[si+2]

         jbe next2

         xchg al,[si+2]

         mov [si],al

next2:

         ;第三次比较

         mov al,[si+1]

         cmp al,[si+2]

         jbe over

         xchg al,[si+2]

         mov [si+1],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.数据定义 

3.al=x   

4.比较判断,0-9,A-F之间       

5.如果是0-9:al+30h

6.如果不是0-9,则是A-F: al+37h

7.ASCII =al    

8.结束 

示例代码34

;例2:写一个实现把一位十六进制数转换为对应的ASCII码的程序

;程序名:t10-10.asm

;功能:十六进制数转换为ASCII码

;算法:0~9 +30H;A~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进制数

算法分析:

假设AL=ASCII码,X为转换后的16进制数,分为7种情况:

1.AL<'0',X=-1;

2.'0'<=AL<='9',X=AL-'0';

3.'9'<AL<'A',X=-1;

4.'A'<=AL<='F',X=AL-'A'+10 ;

5.'F'<AL<'a',x=-1;

6.'a'<=AL<='f' x=AL-'a'+10;

7.AL>'f',x=-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汇编语言基础教程》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/713710.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络【网络安全】

计算机网络——网络安全 一、网络安全问题概述 网络安全威胁 网络安全面临两大类威胁&#xff0c;被动攻击和主动攻击 被动攻击 指攻击者从网络上窃听他人的通信内容&#xff0c;通常把这类攻击称为截获。 主动攻击 篡改 攻击者故意篡改网络上传送的报文 恶意程序 拒绝服…

12、窗口看门狗

目录 1、窗口看门狗概述 2、常用寄存器和库函数配置 3、窗口看门狗实验 1、窗口看门狗概述 之所以称为窗口就是因为其喂狗时间是一个有上下限的范围内&#xff08;窗口&#xff09;&#xff0c;你可以通过设定相关寄存器&#xff0c;设定其上限时间&#xff08;下限固定&…

技术栈选型的时候,ruby、go、java、vue、react应该怎么选择?

选择适合项目需求、团队技术背景和偏好、开发速度、性能要求以及可扩展性的技术栈和框架是一个综合考虑的过程&#xff0c;没有一种通用的最佳选择&#xff0c;取决于具体情况。 选择Vue.js或React应该综合考虑项目的需求、团队的技术背景和偏好、生态系统的支持和发展趋势等因…

WPF真入门教程30--顺风物流单据管理系统

1、教程回顾 到现在为止&#xff0c;真入门系列教程已完成了29刺由浅入深地讲解&#xff0c;当然不可能讲到了WPF的所有技能点&#xff0c;但读者看到了wpf的内部各种功能及之间的联系&#xff0c;在此基础上&#xff0c;提供一个完整有效的综合项目&#xff0c;本项目采用的是…

加密与安全_深入了解Hmac算法(消息认证码)

文章目录 PreHMAC概述常见的Hmac算法Code随机的key的生成 KeyGeneratorHmacMD5用Hmac算法取代原有的自定义的加盐算法 HmacMD5 VS MD5HmacSHA256 Pre 加密与安全_深入了解哈希算法中我们提到&#xff0c; 存储用户的哈希口令时&#xff0c;要加盐存储&#xff0c;目的就在于抵…

操作系统系列学习——CPU管理的直观想法

文章目录 前言CPU管理的直观想法 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招&#xff0c;计划学习操作系统并完成6.0S81&#xff0c;加油&#xff01; 本文总结自B站【哈工大】操作系统 李治军&#xff08;全32讲&#xff09; 老师课程讲的非常好&#xff0c;感谢 【…

OpenLayers线性渐变和中心渐变(径向渐变)

目录 1.前言2.添加一个面要素3.线性渐变3.1 第一个注意点3.2 第二个注意点 4.中心渐变&#xff08;径向渐变&#xff09;5.总结 1.前言 OpenLayers官网有整个图层的渐变示例&#xff0c;但是没有单个要素的渐变示例&#xff0c;我们这里来补充一下。OpenLayers中的渐变是通过fi…

编译链接实战(22)C/C++代码覆盖率统计报告生成

文章目录 GCOV 工具简介gcov 使用lcov相关编译选项 GCOV 工具简介 gcov是一个测试代码覆盖率的工具&#xff0c;它是 gcc 自带的查看代码覆盖率的工具。 与GCC结合使用&#xff0c;可以分析您的程序以帮助创建更高效、运行更快的代码&#xff0c;并发现程序中未经测试的部分。…

PCIE 4.0 L0s/L1/L2

L0是PCIE设备正常工作的状态&#xff0c;当设备链路处于非工作状态可以跳转大相应的低功耗状态&#xff0c;L0s是一种可以快速恢复到L0的低功耗状态&#xff1b;L1必须经过Reovery状态才可以恢复到L0状态&#xff1b;L2需要从Detect开始逐步进入到L0状态。它们的恢复时间依次延…

麒麟银河操作系统V10部署ffmpeg(也能用于Linux系统)

麒麟银河操作系统V10部署ffmpeg(也能用于Linux系统) 部署ffmpeg用来处理视频的各种操作 想使用ffmpeg&#xff0c;要先安装nasm&#xff0c;yasm&#xff0c;x264之后&#xff0c;否则会报错 nkvers 查看麒麟操作系统版本 cat /proc/version #查看linux版本信息 uname -a …

Android修行手册-Chaquopy中opencv、numpy的初步应用

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

SpringBoot源码解读与原理分析(三十八)SpringBoot整合WebFlux(一)WebFlux的自动装配

文章目录 前言第13章 SpringBoot整合WebFlux13.1 响应式编程与Reactor13.1.1 命令式与响应式13.1.2 异步非阻塞13.1.3 观察者模式13.1.4 响应性13.1.5 响应式流13.1.6 背压13.1.7 Reactor13.1.7.1 Publisher13.1.7.2 Subscriber13.1.7.3 Subscription13.1.7.4 Processor13.1.7.…

Leetcoder Day32| 贪心算法part05

763.划分字母区间 字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。 示例&#xff1a; 输入&#xff1a;S "ababcbacadefegdehijhklij"输出&#xff1a;[9,7…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 3月2日,星期六

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年3月2日 星期六 农历正月廿二 1、 气象局&#xff1a;3月份仍有5次冷空气影响我国&#xff1b;全国多地或提前入春。 2、 央行&#xff1a;将外籍来华人员移动支付单笔交易限额由1000美元提高到5000美元。 3、 神舟十七号航…

【源码】imx6ull实现触摸屏单点实验

一、本实验实验的器材&#xff1a; 1.正点原子imx6ull的阿尔法开发板v2.2 2.屏幕ALIENTEK 4.3 RGBLCD 二、实验已经移植好的文件&#xff1a; 仓库代码&#xff1a;https://gitee.com/wangyoujie11/atkboard_-linux_-driver.git 1.文件说明 23_multitouch &#xff1a;驱动代…

【YOLO v5 v7 v8 小目标改进】ODConv:在卷积核所有维度(数量、空间、输入、输出)上应用注意力机制来优化传统动态卷积

ODConv&#xff1a;在卷积核所有维度&#xff08;数量、空间、输入、输出&#xff09;上应用注意力机制来优化传统的动态卷积 提出背景传统动态卷积全维动态卷积效果 小目标涨点YOLO v5 魔改YOLO v7 魔改YOLO v8 魔改 论文&#xff1a;https://openreview.net/pdf?idDmpCfq6Mg…

leedcode刷题--day7(字符串)

23 文章讲解 力扣地址 C class Solution { public:void reverseString(vector<char>& s) {int left 0;int right s.size() - 1; // right 应该初始化为 s.size() - 1while (left < right) {swap(s[left], s[right]); // 直接交换 s[left] 和 s[right] 的值lef…

(学习日记)2024.02.29:UCOSIII第二节

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

WSL2外部网络设置

1 关闭所有WSL系统 wsl --shutdown 2 打开Hyper-V管理器 3 将“虚拟交换机管理器”-> ”WSL连接类型“设置为“外部网络” 4 启动WSL系统&#xff0c;手动修改WSL网络 将WSL网络IP修改为192.168.1.9 sudo ip addr del $(ip addr show eth0 | grep inet\b | awk {print $2} |…

FinalMLP:用于推荐系统的简单但强大的双流 MLP 模型

原文地址&#xff1a;FinalMLP: A Simple yet Powerful Two-Stream MLP Model for Recommendation Systems 了解 FinalMLP 如何转变在线推荐&#xff1a;通过尖端 AI 研究解锁个性化体验 2024 年 2 月 14 日 介绍 世界正在向数字时代发展&#xff0c;在这个时代&#xff0c;…