Assembly 汇编8086 |数组之和,打印多位数

Assembly 汇编8086 |数组之和,打印多位数,assembly,x86-16,Assembly,X86 16,我已经用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:

我已经用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])将
add
替换为
mov
,这样的更正只不过是标签EndLoop处的函数调用出错了

您希望显示总和,并且正在使用DOS打印功能。此函数09h需要DS:DX中的一个指针,而您没有提供该指针
即使您这样做了,您仍然必须转换其文本表示形式中的和数

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

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

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

exit:
    mov ax, 4c00h
    int 21h
再进一步,我们可以显示“52”:


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

您可能想显示总和的结果

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

因此,您需要两件事,将
[sum]
中的数字转换为结尾以
'$'
结尾的字符串,然后将
dx
设置为该
int 21h
前面的转换字符串

您可以尝试从此处提取
number2string
过程:

我个人会将其更改为将
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 ...

注意:add al,[bx]这一行实际上是mov al,[bx]我想这里有一个简单的解释:(目前还不清楚你在问什么)另外,对于汇编,它总是有助于指定运行代码的目标平台/操作系统,以及编译代码时使用的汇编程序(即使复制所使用的命令行也不要犹豫,有时甚至可能有助于解决问题)。我的意思是,很少有人会查看您的源代码,并且拥有相同的环境,因此他们可以复制/粘贴它,编译并实时查看您的问题。这里的大多数人都会利用他们的知识和经验进行“试运行”在他们的头脑中,为了让他们更容易理解,你应该提供每一个相关的细节(想象一下你自己在阅读问题时对你的设置一无所知)。如果它只是直接存储到缓冲区中,并在div循环中执行
dec si
,而不是推到堆栈上并在单独的循环中弹出,则会更简单、更高效。对于使用
int 21h
/
ah=9
打印,您不必关心字符串在缓冲区中的起始位置,只需要一个指向起始位置的指针.
    ; 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 ...