继续从作业代码出发来学习知识点
任务一
题目:
代码
.model small
.stack 100h
.data
scores db 46, 68, 88, 87, 76, 89, 99, 65, 100, 80 ; 学生成绩
S5 db 0 ; 低于60分人数
S6 db 0 ; 60-69分人数
S7 db 0 ; 70-79分人数
S8 db 0 ; 80-89分人数
S9 db 0 ; 90-99分人数
S10 db 0 ; 100分人数
.code
main proc
mov cx, 10 ; 循环次数
lea si, scores ; 成绩数组指针
check_score:
lodsb ; 读取一个成绩到 AL
cmp al, 60
jl below_60
cmp al, 70
jl between_60_69
cmp al, 80
jl between_70_79
cmp al, 90
jl between_80_89
cmp al, 100
jl between_90_99
jmp exactly_100
below_60:
inc S5 ; 低于60分人数加1
jmp next_score
between_60_69:
inc S6 ; 60-69分人数加1
jmp next_score
between_70_79:
inc S7 ; 70-79分人数加1
jmp next_score
between_80_89:
inc S8 ; 80-89分人数加1
jmp next_score
between_90_99:
inc S9 ; 90-99分人数加1
jmp next_score
exactly_100:
inc S10 ; 100分人数加1
next_score:
loop check_score ; 循环直到所有成绩处理完毕
; 程序结束
mov ax, 4C00h
int 21h
main endp
end main
- 段定义和数据初始化
.model small
.stack 100h
.data
scores db 46, 68, 88, 87, 76, 89, 99, 65, 100, 80 ; 学生成绩
S5 db 0 ; 低于60分人数
S6 db 0 ; 60-69分人数
S7 db 0 ; 70-79分人数
S8 db 0 ; 80-89分人数
S9 db 0 ; 90-99分人数
S10 db 0 ; 100分人数
.data:定义数据段。
scores:定义一个包含10个成绩的字节数组。
S5 到 S10:定义用于存储各分数段人数的字节变量,并初始化为 0。
Db:是define byte的缩写,用于在数据中定义一个或多个字节数据,允许程序员在内存中分配和初始化一个或多个字节的存储空间。
- 代码段和主程序
.code
main proc
mov cx, 10 ; 循环次数
lea si, scores ; 成绩数组指针
- main proc:定义主过程
1.CX寄存器,(1)作为循环计数器
CX 常用于循环操作中,用来保存循环的次数。
在使用 LOOP 指令时,CX 会自动减少,并在其值为零时结束循环。
(2)在字符串操作中的用途:
·CX 常用于字符串指令(如 REP MOVSB、REP STOSB 等)中,指定要操作的字节数或字数。
- Si寄存器是源索引寄存器
- SI 寄存器通常用作源指针,用于字符串操作和数组处理。
- 在字符串操作指令(如 LODSB, LODSW)中,SI 指向源数据的起始地址,并在操作完成后自动更新。
LEA 指令
- LEA 指令用于加载内存地址到寄存器中,而不是加载内存地址所指向的数据。
- 语法:LEA dest, source
- dest 是目标寄存器。
- source 是内存地址表达式。
LEA 指令的主要作用是计算复杂的地址表达式,而不会实际访问内存。
- 分数段判断和统计
check_score:
lodsb ; 读取一个成绩到 AL
cmp al, 60
jl below_60
cmp al, 70
jl between_60_69
cmp al, 80
jl between_70_79
cmp al, 90
jl between_80_89
cmp al, 100
jl between_90_99
jmp exactly_100
- lodsb:从 si 指针指向的内存地址加载一个字节到 al,并自动增加 si。
- cmp al, 60:比较 al 和 60。
- jl below_60:如果 al 小于 60,跳转到 below_60 标签。
- 依此类推,继续比较 al 和其他分数段的上限值,并跳转到相应的处理标签。
jl是一个跳转指令,表示“如果小于则跳转(jump if less)”
- 统计各分数段人数
below_60:
inc S5 ; 低于60分人数加1
jmp next_score
between_60_69:
inc S6 ; 60-69分人数加1
jmp next_score
between_70_79:
inc S7 ; 70-79分人数加1
jmp next_score
between_80_89:
inc S8 ; 80-89分人数加1
jmp next_score
between_90_99:
inc S9 ; 90-99分人数加1
jmp next_score
exactly_100:
inc S10 ; 100分人数加1
next_score:
loop check_score ; 循环直到所有成绩处理完毕
; 程序结束
mov ax, 4C00h
int 21h
main endp
end main
任务二:(2)
.model small
.stack 100h
.data
#$是一个字符串结束的标志
prompt db 'Enter a lowercase letter: $'
#newline表示可以将光标移动到下一行的开头
#‘0Dh’是回车字符,将光标移动到当前行的开头
#‘0Ah’是换行字符 ,将光标移动下一行
newline db 0Dh, 0Ah, '$'
output db '$'
.code
main proc
#将@data的段地址 加载到ax寄存器中
#复习逻辑地址:由段地址和偏移地址构成
mov ax, @data
#ds数据段寄存器
mov ds, ax
#es附加段寄存器
mov es, ax
#这是一个标签label,表示程序或循环的开始位置。以便可以使用跳转指令(如jmp)跳转到该位置
start:
# lea指令:是“加载有效地址(load effective address)的缩写”
#dx是目标寄存器,用于存放有效地址
#这段代码将prompt字符串的地址加载到dx寄存器中,而不是加载字符串的内容
lea dx, prompt
#ah是ax寄存器的高字节。09h是dos的一个中断服务号,用于显示字符串
#这里将‘09h’移动到‘ah’寄存器中,告诉DOS要调用的是显示字符串服务
mov ah, 09h
#int指令用于触发终端
#‘21h’是DOS的中断号,负责各种服务系统。
#当‘ah’寄存器中包含‘09h’时,调用‘21h会除法显示字符串操作’
#dx寄存器应包含要显示的字符串地址,该字符串必须以’$’结尾。
int 21h
; 读取键盘输入
#将01h移动到ah寄存器中
mov ah, 01h
#dos中断21h的上下文,‘ah’寄存器的值决定了要执行的具体功能,‘01h’的功能号表示读取键盘输入的一个字符,但字符不会显示在屏幕上
int 21h
#al寄存器包含刚刚输入的值
mov bl, al ; 保存输入字符
; 检查是否是小写字母
cmp al, 'a'
jb end_program ; 如果小于 'a',结束程序
cmp al, 'z'
ja end_program ; 如果大于 'z',结束程序
; 转换为大写字母
#小写字母‘a’到‘z’的asc码是97到122(16进制为61h到7Ah)
#大写字母‘A’到‘Z’的asc码是65到90(16进制为41h到5Ah)
#小写字母和对应大写字母 之间的差值是32(十六进制为20h)
sub al, 20h
; 显示大写字母
mov output, al
lea dx, output
mov ah, 09h
int 21h
; 显示新行
lea dx, newline
mov ah, 09h
int 21h
jmp start ; 返回开始,继续读取输入
end_program:
; 程序结束
mov ax, 4C00h
int 21h
main endp
end main
- 数据段
解析
.data
prompt db 'Enter a lowercase letter: $'
newline db 0Dh, 0Ah, '$'
output db '$'
- prompt:提示用户输入字符的字符串。
- newline:新行字符,用于在输出后换行。
- output:用于存储并显示转换后的大写字母。
- 代码段
.code
main proc
mov ax, @data
mov ds, ax
mov es, ax
- ds:数据段寄存器
- Es:附加段寄存器es,用于显示字符串
- 条件跳转指令
- jb(jump if below):如果无符号比较结果是小于,则跳转到指定的标签
- ja(jump if above):如果无符号比较结果是大于,则跳转到指定的标签
上面的jl是有符号比较
五.DOS编程:面向磁盘操作系统编程