鱼C论坛

 找回密码
 立即注册
查看: 205|回复: 3

[已解决]本例中or dl ,30h的意图

[复制链接]
发表于 2025-3-28 16:45:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
下面的例子是在给定字符串中查找某个字符,如果找到显示字符相对于字符串的首地址的偏移位置,如果未找到,就显示'N'。
但是我没看懂第22行“or dl,30”这行代码的意图,因为当查找位置大于10时,实际效果是字符转换。

data segment
string        db        'THIS IS A STRING'
count equ $-string
data ends

assume cs:code,ds:data,es:data
code segment

start:        mov ax,data
                mov ds,ax
                mov es,ax
                lea di,offset string
                mov al,'R'
                mov cx,count
                cld
                repne scasb
                jz found
                mov dl,'N'
                jmp display
found:        dec di
                mov dx,di
                or dl,30h
display:mov ah,02h
                int 21h
                mov ah,4ch
                int 21h
               
code ends
end start
               
最佳答案
2025-3-28 18:45:27
本帖最后由 jackz007 于 2025-3-28 18:55 编辑
  1.                 or dl,30h
复制代码

         这一句的作用是把 dl 寄存器中的数字变成对应的文本字符以便利用 DOS 的 AH=02 功能在屏幕上进行显示。例如,dl = 00h,or dl , 30h 后,dl = 30h = '0',再例如,dl = 09h,  or dl , 30h 后,dl = 39h = '9' ,这个操作会把数字 0、9 分别变成对应的字符 '0' 和 '9'。
         但是,本例存在一个问题,那就是字符 'R' 的偏移为十进制 12,也就是说,dl 的值是 0ch,超出了十进制数字 9,是个十进制的两位数(12),就不可以直接 or dl , 30h 了,必须对相关的代码进行修改。
  1. assume cs:code,ds:data,es:data
  2. stack segment stack
  3.               db 400h dup(00)
  4. stack ends
  5. data segment
  6. string        db        'THIS IS A STRING'
  7. count = $ - string
  8. data ends
  9. code segment
  10. start:        mov ax,data
  11.               mov ds,ax
  12.               mov es,ax
  13.               mov di,offset string      ; 这里应该用 mov 指令
  14.               mov al,'R'
  15.               mov cx,count
  16.               cld
  17.               repne scasb
  18.               jz found
  19.               mov dl,'N'
  20.               jmp display
  21. found:        dec di
  22.               mov dx,di
  23.               cmp dx,0ah                ; 判定偏移是否小于十进制 10
  24.               jb x01                    ; 是则跳走
  25.               mov ax,dx                 ; 准备除法操作,被除数赋值
  26.               mov cl,0ah                ; 准备除法操作,除数赋值
  27.               div cl                    ; ax 除以 0ah
  28.               mov dx,ax                 ; dl 是商,dh 是余数
  29.               add dl,30h                ; 把商由数字变成对应的字符
  30.               mov ah,02h                ; 调用 DOS 功能进行屏幕显示
  31.               int 21h                   ; 调用 DOS 功能进行屏幕显示
  32.               mov dl,dh                 ; 准备显示余数
  33. x01:          add dl,30h
  34. display:      mov ah,02h
  35.               int 21h
  36.               mov ah,4ch
  37.               int 21h
  38. code ends
  39. end start
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2025-3-28 18:45:27 | 显示全部楼层    本楼为最佳答案   
本帖最后由 jackz007 于 2025-3-28 18:55 编辑
  1.                 or dl,30h
复制代码

         这一句的作用是把 dl 寄存器中的数字变成对应的文本字符以便利用 DOS 的 AH=02 功能在屏幕上进行显示。例如,dl = 00h,or dl , 30h 后,dl = 30h = '0',再例如,dl = 09h,  or dl , 30h 后,dl = 39h = '9' ,这个操作会把数字 0、9 分别变成对应的字符 '0' 和 '9'。
         但是,本例存在一个问题,那就是字符 'R' 的偏移为十进制 12,也就是说,dl 的值是 0ch,超出了十进制数字 9,是个十进制的两位数(12),就不可以直接 or dl , 30h 了,必须对相关的代码进行修改。
  1. assume cs:code,ds:data,es:data
  2. stack segment stack
  3.               db 400h dup(00)
  4. stack ends
  5. data segment
  6. string        db        'THIS IS A STRING'
  7. count = $ - string
  8. data ends
  9. code segment
  10. start:        mov ax,data
  11.               mov ds,ax
  12.               mov es,ax
  13.               mov di,offset string      ; 这里应该用 mov 指令
  14.               mov al,'R'
  15.               mov cx,count
  16.               cld
  17.               repne scasb
  18.               jz found
  19.               mov dl,'N'
  20.               jmp display
  21. found:        dec di
  22.               mov dx,di
  23.               cmp dx,0ah                ; 判定偏移是否小于十进制 10
  24.               jb x01                    ; 是则跳走
  25.               mov ax,dx                 ; 准备除法操作,被除数赋值
  26.               mov cl,0ah                ; 准备除法操作,除数赋值
  27.               div cl                    ; ax 除以 0ah
  28.               mov dx,ax                 ; dl 是商,dh 是余数
  29.               add dl,30h                ; 把商由数字变成对应的字符
  30.               mov ah,02h                ; 调用 DOS 功能进行屏幕显示
  31.               int 21h                   ; 调用 DOS 功能进行屏幕显示
  32.               mov dl,dh                 ; 准备显示余数
  33. x01:          add dl,30h
  34. display:      mov ah,02h
  35.               int 21h
  36.               mov ah,4ch
  37.               int 21h
  38. code ends
  39. end start
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-3-28 19:57:02 | 显示全部楼层
这是网上一篇教学字符串处理汇编指令文章中的例题,不明白作者怎么没考虑偏移大于9的情况,还一位or dl,30h有其他意思。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-4-2 20:52:12 | 显示全部楼层
关于 OR DL,30H 的解释:

这个指令的作用是将数字转换为对应的ASCII字符。具体分析如下:

当找到字符时:
1. DEC DI 修正偏移量(SCASB会使DI多+1)
2. MOV DX,DI 获取偏移地址(假设偏移量 ≤ 255,此时DL=偏移量)
3. OR DL,30H 将数字转换为ASCII字符:
   - 数字 0 → 30H → '0'
   - 数字 5 → 35H → '5'
   - 数字 10 → 0AH → 0AH OR 30H = 3AH → ':'(这里存在逻辑错误!)

代码缺陷:
当偏移量 ≥10时(即需要显示两位数字时),这个简单转换会失效。正确做法应实现十进制数值转换(比如用DIV指令拆分十位和个位)。

修正建议:

  1. ; 以偏移量15为例的正确转换方法:
  2. found:  dec di
  3.         mov ax,di       ; 获取偏移量
  4.         mov bl,10
  5.         div bl          ; AH=个位,AL=十位
  6.         add ax,3030h    ; 同时转换十位和个位为ASCII
  7.         mov dx,ax        ; DH=十位字符,DL=个位字符
  8.         ; 需要分别输出两个字符
复制代码


以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-10 02:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表