【问题标题】:How to count number of vowels in a string in 8086 ALP?如何计算 8086 ALP 中字符串中元音的数量?
【发布时间】:2019-02-20 13:13:59
【问题描述】:

我编写了一个汇编程序,它计算用户读取的字符串中元音的数量。字符串的读取和长度的计算工作正常。但是在比较字符串的字符时,前两个字符不起作用。这是我的代码。

.MODEL small
.STACK
.DATA
 input db 10,?
 length db ?
 count db ?
.CODE
.STARTUP 
 ;reading string
 mov dx,00h
 mov dx,offset input
 mov ah,0Ah
 int 21h 

 ;calculating length
 mov length,00h
 mov si,offset input+2

 ;checking for vowels
 loopi: cmp [si],'$'
    je next
    add length,01h
    inc si
    loop loopi
 next:
    mov cx,00h
    mov cl,length 

    mov si,offset input+2 
    mov count,00h
 counting:cmp [si],'a'
      je count1 
      cmp [si],'e'
      je count1
      cmp [si],'i'
      je count1
      cmp [si],'o'
      je count1
      cmp [si],'u'
      je count1
      inc si
      loop counting
      cmp cl,00h
      je exit
  count1:inc count 
      inc si
     loop counting 
 exit: 
.EXIT
 end

此代码不比较/检查字符串的前两个字符。有人可以尽快帮助我吗? 任何帮助将不胜感激。非常感谢。

【问题讨论】:

    标签: assembly user-input x86-16 emu8086


    【解决方案1】:

    字符串的读取和长度的计算工作正常。但是在比较字符串的字符时,它不适用于前两个字符。

    碰巧,正是比较部分很好!你的烦恼从输入开始就存在,因为你不明白问号在汇编编程中的作用。

    input db 10,?
    length db ?
    count db ?
    

    在所有这些行中,问号 ? 代表一个字节,大多数(如果不是全部)汇编程序会将其初始化为零值 0。你得到的是:

    input  db 10, 0
    length db 0
    count  db 0
    

    这对于 lengthcount 来说很好,但对于应该是 the DOS buffered input function 0Ah 的输入缓冲区的 input 则不然。您确实没有所需的存储空间。错误地覆盖了 lengthcount 等的内存!

    解决方案是input db 10, 0, 10 dup (?)。这允许输入 9 个字符。为什么是9?因为 DOS 总是在输入后面附加一个回车 13,而这个回车也需要在 10 dup (?) 定义的这个 10 字节存储空间中的一个字节。

    这个回车也解释了为什么你的长度计算会失败。当您应该搜索 ASCII 代码 13 时,您正在搜索“$”。

    当然,计算长度是多余的,因为 DOS 已经通知你了。输入结构的第二个字节长度。

    mov cx, 0
    mov cl, [input+1] ; length 
    

    大家一起:

    .DATA
     input  db 10, 0, 10 dup (?)
     count  db ?
    .CODE
    .STARTUP 
     ;reading string
        mov  dx, offset input
        mov  ah, 0Ah
        int  21h 
    
     ;checking for vowels
        xor  cx, cx            ; Also clears the CX register like `mov cx, 0`
        mov  count, cl         ; Count = 0
        mov  si, offset input+2 
        mov  cl, [si-1]        ; length is 2nd byte
     counting:
        cmp  [si], 'a'
        je   count1 
        cmp  [si], 'e'
        je   count1
        cmp  [si], 'i'
        je   count1
        cmp  [si], 'o'
        je   count1
        cmp  [si], 'u'
        je   count1
        inc  si
        loop counting
        cmp  cl, 0        \ You can replace these 2 by
        je   exit         / a single `jmp exit`
     count1:
        inc  count 
        inc  si
        loop counting 
     exit: 
    .EXIT
    

    更好的解决方案

    • 不使用慢速loop 指令
    • 最小化内存访问
    • 使用字符串原语,如lodsb
    • 如果字符串为空,则不会失败!
    • 尽量减少跳跃次数

    在这里展示:

     ;checking for vowels
        cld                ; For completeness because `lodsb` depends on it
        mov  si, offset input+2 
        mov  dl, -1
     vowel:
        inc  dl
     other:
        lodsb              ; This is `mov al, [si]` followed by `inc si`
        cmp  al, 'a'
        je   vowel 
        cmp  al, 'e'
        je   vowel
        cmp  al, 'i'
        je   vowel
        cmp  al, 'o'
        je   vowel
        cmp  al, 'u'
        je   vowel
        cmp  al, 13
        jne  other
        mov  count, dl
    

    【讨论】:

    • 这被标记为emu8086loop 在真正的 8086 上或可能在模拟器上本身并不慢。如果您可以使用更少(或更小)的指令,例如 cmp/jcc 而不是使用单独的 reg 作为循环计数器,那么它只会很慢。当然,它在 modern x86 上通常不是很有用。但lodsb 也不是(3 uops 并且对旧 RAX 有错误的依赖)。 Haswell 和后来有高效的lodsdlodsq(2 微秒),但推荐lodsb 以及避免loop 是不明智的。当然 8086 没有movzx 以避免部分注册错误依赖...
    • 如果你想谈谈效率,如果我们有 386,那么我们可以有效地检查以c - 'a' 为索引的 32 位位图。请参阅User Appreciation Challenge #1: Dennis ♦ 以获取我用bt 测试的辅音的32 位立即位图,在向上转换和范围移动以获得字母的0..25 字母位置之后。我没有看到一种简单的方法可以将它用于 8086,它比 cmp/jcc on 8086 链更有效(其中分支未命中不是问题)。
    • 对我这样的初学者真的很有帮助。我尝试在我的程序中实现它并且它有效。非常感谢。
    猜你喜欢
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2020-12-12
    • 2021-06-09
    • 2020-02-19
    • 1970-01-01
    • 2020-08-07
    • 2020-10-02
    相关资源
    最近更新 更多