文章目录
前言
本文是王爽老师《汇编语言》(第四版) 第十一章 实验11 的分析及代码,并在此基础上做了小小的优化,方便直观地进行程序测试。
一、实验任务
编写一个子程序,将包含任意字符,以0结尾的字符串中的小写字母转变成大写字母。
名称:lectterc
功能:将以0为结尾的字符串中的小写字母转变成大写字母
参数:ds:si指向字符串首地址
assume cs:code,ds:data
data segment
db 'welcome to masm!haha,I am happy!',0
data ends
code segment
start:
mov ax,data
mov ds,ax
mov si,0
call letterc
mov ax,4c00H
int 21H
letterc:
code ends
end start
二、实现思路
用循环遍历每一个字符字节,检测是否为小写字母。根据书上给出的例子的思路,先判断 “若不是”,则直接跳转下一个;再判断 “若是”,则转为大写字母,然后跳转下一个。遇到0则结束循环,程序返回。
三、实现代码
assume cs:code,ds:data
data segment
db 'welcome to masm!haha,I am happy!',0
data ends
code segment
start:
mov ax,data ;设置ds:si指向data段字符串首地址
mov ds,ax
mov si,0
call letterc
mov ax,4c00H ;程序返回
int 21H
;函数:将字符串转为大写
letterc:
;功能:将指定位置、任意长度、以0结尾的字符串中
; 所有小写字母转为大写字母
;参数:ds:si指向字符串首地址
;返回:无
;实现思路:用循环遍历每一个字符字节,检测是否为
;小写字母,若是,则转为大写字母,否则下一个。
;遇到0则结束循环,程序返回。
push cx ;将用到的寄存器压入栈
push si
mov cx,0 ;初始化
s: ;循环体
mov cl,ds:[si] ;取当前字符字节
jcxz ok ;若当前字节为0,则结束循环,跳转
cmp cx,61H ;与字符'a'比较
jb next ;若<字符'a'则跳转
cmp cx,7AH ;与字符'z'比较
ja next ;若>字符'z'则跳转
sub cx,20H ;执行这句的,就是小写字母,则转大写
mov ds:[si],cl ;将大写字母存到内存中
jmp next ;转换后也跳转到下一个
next: ;取下一个字符
inc si
loop s ;重新执行循环
ok: ;程序返回
pop si ;在返回前将寄存器的值pop出来
pop cx
ret
code ends
end start
四、DIY时间
1.需求分析
这一章的实验出奇地简单,微微有些不适应。于是决定自己动手增加一些功能,也当作对之前知识的复习。
这个实验,每次测试,都需要手动查看相关内存地址中的数据,才能判断程序是否运行正确。这有点麻烦。既然已经学过了向显存中复制数据的知识,那么我决定将转换前与转换后的字符串都显示在屏幕上,这样,转换是否正确就一目了然!
这里需要用到的子程序功能,就是将指定字符串显示在屏幕指定位置。这个子程序在之前的实验中已经写过,但是这里使用这一章学习的movsb传送指令,修改一下原先的代码,再重新写一次。正好也可以复习之前的知识。
这样,在主程序中,只要在调用 letterc子程序的前后各调用一次用于显示字符串的程序(注意要指定不同的显示行号),就能在屏幕上分别显示出转换前后的字符串了。
2.最终效果
显示效果如下。
3.实现代码
完整的代码如下。
assume cs:code,ds:data
data segment
db 'welcome to masm! haha,I am happy!',0
data ends
stack segment
db 0
stack ends
code segment
start:
;设置段地址
mov ax,data ;设置ds指向data段
mov ds,ax
mov ax,stack ;设置ss指向stack段
mov ss,ax
mov sp,10H
;显示原始字符串
mov dh,08H ;指定屏幕显示的行号
mov dl,3H ;指定屏幕显示的列号
mov bl,0CH ;指定屏幕显示的字符属性
call show_str ;将转换前的字符串显示在屏幕上
;进行大小写转换
mov si,0 ;ds:si指向data段字符串首地址
call letterc ;将小写字母转为大写字母
;显示转为大写后的字符串
mov dh,0DH ;指定屏幕显示的行号
mov dl,3H ;指定屏幕显示的列号
mov bl,2H ;指定屏幕显示的字符属性
call show_str ;将转换后的字符串显示在屏幕上
mov ax,4c00H ;程序返回
int 21H
;函数:显示字符串
show_str:
;功能:将指定位置、任意长度、以0结尾的字符串显示
; 在屏幕指定位置上。
;参数:ds:si指向字符串首地址,dh是指定行号,dl是指定列号,
; bl是指定属性字节
;返回:无
;实现思路:利用movsb传送指令,将指定字符串传送到显存地址中
push es ;将用到的寄存器压入栈暂存
push di
push si
push ax
push dx
push cx
mov ax,0B800H ;设置es指向显存区域段地址
mov es,ax
mov ax,0A0H ;计算显存中首字符的偏移地址
mul dh
mov dh,0
add ax,dx ;一个字符占2个字节,所以要加上 2*dl
add ax,dx
mov di,ax ;将显存中首字符偏移地址赋值给di
mov cx,0 ;初始化
cld ;设置DF标志位为0,传送正向进行
show_next: ;逐个字符进行显示
mov cl,ds:[si] ;取一个字符字节
jcxz show_ok ;若当前字节为0,则跳转
movsb ;从ds:[si]向es:[di]传送一个字节,之后自动si+1,di+1
mov es:[di],bl ;将属性字节复制到显存中
inc di
jmp show_next
show_ok: ;程序返回
pop cx ;将寄存器的值pop出来
pop dx
pop ax
pop si
pop di
pop es
ret
;函数:将字符串转为大写
letterc:
;功能:将指定位置、任意长度、以0结尾的字符串中
; 所有小写字母转为大写字母
;参数:ds:si指向字符串首地址
;返回:无
;实现思路:用循环遍历每一个字符字节,检测是否为
;小写字母,若是,则转为大写字母,否则下一个。
;遇到0则结束循环,程序返回。
push cx ;将用到的寄存器压入栈
push si
mov cx,0 ;初始化
s: ;循环体
mov cl,ds:[si] ;取当前字符字节
jcxz ok ;若当前字节为0,则结束循环,跳转
cmp cx,61H ;与字符'a'比较
jb next ;若<字符'a'则跳转
cmp cx,7AH ;与字符'z'比较
ja next ;若>字符'z'则跳转
sub cx,20H ;执行这句的,就是小写字母,则转大写
mov ds:[si],cl ;将大写字母存到内存中
jmp next ;转换后也跳转到下一个
next: ;取下一个字符
inc si
loop s ;重新执行循环
ok: ;程序返回
pop si ;在返回前将寄存器的值pop出来
pop cx
ret
code ends
end start
总结
本文是王爽老师《汇编语言》(第四版) 第十一章 实验10 的分析及代码,并在此基础上做了小小的优化。通过这个实验,主要复习了cmp指令以及对应的条件转移指令,顺道复习了向显存中写入数据的方法以及movsb传送指令。