【问题标题】:Assembly 8086 | Sum of an array, printing multi-digit numbers组装 8086 |数组的总和,打印多位数字
【发布时间】:2018-03-23 20:22:45
【问题描述】:

我在 asm x8086 中编写了一个非常简单的代码,但遇到了一个错误。如果有人能帮我做一个简短的解释,我将不胜感激。

IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
    array db 10h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h
    sum db 0
    ; --------------------------
CODESEG
start:
    mov ax, @data
    mov ds, ax
; --------------------------
    xor cx, cx
    mov al, 0
    mov bx, offset array
StartLoop:
    cmp cx, 10
    jge EndLoop
    add al, [bx]
    add [sum],al
    inc cx
    inc bx
    jmp StartLoop
EndLoop:
    mov ah, 09h
    int 21h

; --------------------------

exit:
    mov ax, 4c00h
    int 21h
END start

【问题讨论】:

  • 注意这一行:add al, [bx] 实际上是 mov al, [bx]
  • 我认为这里有一个简短的解释:stackoverflow.com/help/how-to-ask(目前尚不清楚您在问什么)另外,对于组装,它总是有助于指定您的目标平台/操作系统来运行代码,以及你使用什么汇编器来编译它(即使复制使用的命令行也不要犹豫,有时甚至可能有助于解决问题)。
  • 我的意思是,很少有人会查看您的源代码,并且拥有相同的环境,因此他们可以复制/粘贴它,编译并实时查看您的问题。这里的大多数人将利用他们的知识和经验在他们的脑海中进行“试运行”,并且为了让他们更容易,您应该提供所有相关的细节(想象一下自己阅读您的问题时对您的设置外观的了解为零)。

标签: assembly x86-16


【解决方案1】:

add 的更正替换为mov,如您的评论中所述(请注意,该行:add al, [bx] 实际上是 mov al, [bx] ) 只有标签 EndLoop 处的函数调用是错误的!

您想显示总和,并且正在使用 DOS 打印功能。此函数 09h 需要您未提供的 DS:DX 中的指针!
即使你这样做了,你仍然需要在其文本表示中转换 sum 数字。

这里的一个快速解决方案是满足自己并以单个 ASCII 字符的形式显示结果。硬编码的总和是 52,所以它是一个可显示的字符:

EndLoop:
    mov dl, [sum]
    mov ah, 02h    ;Single character output
    int 21h

; --------------------------

exit:
    mov ax, 4c00h
    int 21h

再进一步,我们可以显示“52”:

mov al,[sum]
mov ah,0
mov dl,10
div dl        ---> AL=5   AH=2
add ax,3030h  ---> AL="5" AH="2"
mov dh,ah     ;preserve AH
mov dl,al
mov ah,02h
int 21h
mov dl,dh     ;restore
int 21h

【讨论】:

    【解决方案2】:

    我没有看到任何错误,代码将对数组求和,显示一些随机的 sh*t,然后退出。

    您可能想显示 sum 的结果?

    int 21h, ah=9 将显示来自dx 指向的内存中的'$' 终止字符串。

    所以你需要做两件事,将[sum] 中的数字转换为以'$' 结尾的字符串,然后将dx 设置为int 21h 之前的转换字符串。

    您可以尝试从这里提取number2string 过程:https://stackoverflow.com/a/29826819/4271923

    我会亲自将其更改为将si 中的目标缓冲区地址作为另一个调用参数(即,只需从过程主体中删除mov si,offset str)。像这样:

    PROC number2string
      ; arguments:
      ;  ax = unsigned number to convert
      ;  si = pointer to string buffer (must have 6+ bytes)
      ; modifies: ax, bx, cx, dx, si
        mov  bx, 10  ; radix 10 (decimal number formatting)
        xor  cx, cx  ; counter of extracted digits set to zero
    number2string_divide_by_radix:
      ; calculate single digit
        xor  dx, dx  ; dx = 0 (dx:ax = 32b number to divide)
        div  bx      ; divide dx:ax by radix, remainder will be in dx
      ; store the remainder in stack
        push dx
        inc  cx
      ; loop till number is zero
        test ax, ax
        jnz  number2string_divide_by_radix
      ; now convert stored digits in stack into string
    number2string_write_string:
        pop  dx
        add  dl, '0' ; convert 0-9 value into '0'-'9' ASCII character encoding
      ; store character at end of string
        mov  [si], dl
        inc  si
      ; loop till all digits are written
        dec  cx
        jnz  number2string_write_string
      ; store '$' terminator at end
        mov  BYTE PTR [si],'$'
        ret
    ENDP
    

    然后要在您的 EndLoop 调用它,您需要添加到数据段 numberStr DB 8 DUP (0) 为字符串分配一些内存缓冲区并添加到代码中:

        ; load sum as 16b unsigned value into ax
          xor  ax,ax      ; ax = 0
          mov  al,[sum]   ; ax = sum (16b zero extended)
        ; convert it to string
          mov  si,OFFSET numberStr
          call number2string
        ; display the '$' terminated string
          mov  dx,OFFSET numberStr
          mov  ah,9
          int  21h
        ; ... exit ...
    

    【讨论】:

    • 如果它直接存储到缓冲区中并在 div 循环中执行dec si,而不是压入堆栈并在单独的循环中弹出,这将更简单,更有效。对于使用int 21h/ah=9 进行打印,您并不关心字符串在缓冲区中的哪个位置,您只需要一个指向开始的指针。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多