【问题标题】:Assembly x86 - counting small letters in a file汇编 x86 - 计算文件中的小写字母
【发布时间】:2015-06-09 15:17:34
【问题描述】:

我正在执行一项任务,但不知何故被卡住了。 这是代码的一部分,一定是错误的。实际上错误的是,当程序应该打印数字时(通过过程 convertNumber,它工作得很好!),它什么也不做,也不返回。它只是没有反应,我必须手动关闭它。

read:
            mov ah, 3fh                 ; function for reading from file
            mov bx, handle              ; moving file handle to BX
            mov cx, 10000               ; how many bytes will be read
            mov dx, buffer              ; where the string will be saved
            int 21h                     ; system call ready

            mov bytesRead, 0            ; nulling my variable bytesRead, which represents how many bytes have been read
            mov bytesRead, ax           ; now moving the real value from AX

            cmp ax, 0                   ; if it is equal to 0, then there is nothing left to read                                                     
            je closeFile                ; close file

            mov cx, 0                   ; starting position

cycle:
            cmp cx, bytesRead           ; if I need to reload buffer
            jge read

            mov bx, 0                   ; nulling position counter
            mov bx, cx                  ; moving CX to BX -> mov ax, buffer[cx] was an illegal operation, so I did it this way
            mov ax, buffer[bx]          ; getting a character from BX. position from buffer

            cmp ax, 'a'
            jb next                     ; below 'a', skip
            cmp ax, 'z'
            ja next                     ; above 'z', skip
            inc count_task              ; if it passed, it is between 'a' and 'z'
            jmp next                    ; and moving on

next:
            inc cx                      ; increase position counter (always!)
            jmp cycle                   ; and repeat

finally:
            mov ax, count_task          ; move the final count to AX (needed by the procedure convertNumber)
            call convertNumber          ; convert number to its ASCII value (+48)
            ret

error_fopen:
            print fopenErr
            ret

error_fclose:
            print fcloseErr
            ret

closeFile:
            mov ah, 3eh
            mov bx, handle
            int 21h

            jc error_fclose
            jmp finally

convertNumber proc near
    push si

    mov buff, '$'
    lea si, buff
    mov cx, 10

conv:
    mov dx, 0
    div cx                          ; AX is being divided by CX, where value 10 is stored (direct dividing by 10 is not legal)
    add dx, 48                      ; getting ASCII value of the number (from 0 to '0')
    dec si                          ; going backwards
    mov [si], dl
    cmp ax, 0
    jz printNumber                  ; if AX is empty (0), print the number
    jmp conv                        ; else loop 

printNumber:
    mov ah, 9                       ; service to print string
    mov dx, si                      ; position of my string (number)
    int 21h

    pop si

    ret
convertNumber endp      

我希望你能理解这段代码中发生了什么,如果没有,我可以解释给你。如果有任何帮助,我将不胜感激!

【问题讨论】:

  • 你有很好的标签名称,但你没有评论每一行。如果您对源代码的每一行都提供简短的描述性注释,您将收到更加热情的回应,并获得更多的帮助。
  • 你为什么在mov ax, buffer[bx]之前mov bx,0然后做mov bx,cx?顺便说一句,这将是looplodsb 指令的理想应用程序。你应该检查出来。 :) 正如@User.1 所建议的,出于充分的理由,您应该评论您的说明。有时在这样做的过程中,你会发现问题。
  • 使用调试器单步执行代码,看看哪里出错了。
  • @User.1 是的,对不起,我的错,我现在几乎每一行都评论了
  • 好的,可能依赖于汇编程序。如果大小相同,则无需在加载值之前将 0 加载到某个位置。所以mov ax, 0 后跟mov ax,something 可以是mov ax, something。你应该为你的新任务提出一个新问题。您希望如何打印职位?就像输出中的每行数字一样?

标签: file assembly count letters


【解决方案1】:

使用lodsbloop 的版本如下所示,并整理了一些其他内容。我添加了一些额外的内容来打印找到的每个小写字母的索引。我没有检查这个愚蠢的错误,因为我没有设置运行 DOS 中断。

此代码将处理长度超过 65535 字节的文件,但需要更新“convertNumber”子例程以打印长整数。

编辑:下面的格式假定使用 NASM 汇编器(问题声明中未提及实际使用的汇编器)。

        mov     [count_task], 0
        mov     [count_task+2], 0
        mov     [index], 0
        mov     [index+2], 0
read:
        mov     ah, 3fh                 ; function for reading from file
        mov     bx, [handle]            ; moving file handle to BX
        mov     cx, 10000               ; how many bytes will be read
        mov     dx, buffer              ; where the string will be saved
        int     21h                     ; system call ready
        jc      error_read

        cmp     ax, 0                   ; if it is equal to 0, then there is nothing left to read
        je      finally                 ; print result and close

        ; This code assumes your ds segment register already points to your data

        lea     si, [buffer]
        mov     cx, ax                  ; starting loop counter
        cld                             ; clear direction flag (increment)
cycle:
        lodsb
        cmp     al, 'a'
        jb      next
        cmp     al, 'z'
        ja      next
        add     [count_task], 1
        adc     [count_task+2], 0

        ; Print the current index of the found small letter.
        ; Note it's assumed that convertNumber saves certain registers
        ; according to calling conventions. For example, if it uses "si"
        ; then it should save "si". AX, CX, and DX are fair game.
        ;
        push    cx
        mov     ax, [index]
        mov     dx, [index+2]
        call    convertNumber           ; print the index of the found small letter
        pop     cx
next:
        add     [index], 1              ; increment overall index
        adc     [index+2], 0
        loop    cycle                   ; and repeat

        jmp     read                    ; read another buffer full
finally:
        mov     ah, 3eh
        mov     bx, [handle]
        int     21h
        jc      error_fclose

        mov     ax, [count_task]        ; move the final count to DX:AX (needed by the procedure convertNumber)
        mov     dx, [count_task+2]
        call    convertNumber           ; convert number to its ASCII value (+48)
        ret

error_read:
        print   freadErr
        ret

error_fopen:
        print   fopenErr
        ret

error_fclose:
        print   fcloseErr
        ret

【讨论】:

  • 哦,非常感谢!顺便说一句,标签读取中 count_task 的归零->您认为它会运作良好吗?当我重新加载缓冲区时,字母的数量将被 0 替换,不是吗?我在考虑第二个任务(这些字母的位置),实际上我想在 CX 中打印数字(后跟逗号),但它进入了无限循环,写入 1,1,1,1 或类似的东西,它移动得非常快 :D 来完成这个,你将如何在上面的代码中做到这一点?谢谢
  • @pitbul,哎呀,我的错。 count_task 应在 read 之前设置为 0。 index 也应该如此。为什么要写CX 中的内容?那只是一个寄存器。你到底想写什么才是真正的问题。 CX 应该只保存一个可以帮助您的程序执行循环的值。我的循环结构与你的不同,因为CX 使用loop 指令倒计时。
  • 它发生了 :) 我在 CX 中保留了字符串中的实际位置,所以我想打印它......我注意到,你用其他方式做了(也更好:))跨度>
  • @pitbul 是的,我想使用loop,这意味着cx必须是循环计数器。
  • 是的,我知道它是如何工作的 :) 另外,我的程序应该能够打开超过 128 KB 的文件,你会怎么做?以及如何定义索引变量?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-25
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 2018-08-13
相关资源
最近更新 更多