无法在以下8086汇编代码中使用数组显示负数

时间:2017-02-19 10:08:20

标签: assembly x86-16

我想做什么

我正在尝试使用数组打印一系列负数和正数。

有什么问题

我无法打印负数。

输入:

2,-3,-4,5,2,9

输出:

2-,529

我的8086汇编代码:

.model small
.stack 100h
.data                   
     elements db 2,-3,-4,5,2,9,'#'
.code

     mov ax, @data
     mov ds, ax  

     mov al, 03h
     mov ah, 0
     int 10h    
     mov si, 0
     ;lea si, elements

dis:

     cmp elements[si], '#'
     je exit

     mov dl, elements[si]
     add dl, 48
     mov ah, 02h
     int 21h     
     inc si 
     loop dis
exit:    
     mov ah, 04ch
     int 21h    
end

注意:我是一个完整的初学者。

3 个答案:

答案 0 :(得分:2)

您的计划有两个主要问题:

  1. 您正在使用loop指令而未事先初始化计数器寄存器CX!幸运的是,您的代码在CX寄存器之上有一个额外的终止条件,可能从零开始。然后认为你在这个程序中甚至不需要这个指令。

  2. 您永远不会测试您从阵列中读取的数字是正数还是负数。

  3. 以下是一个包​​含其他重要评论的完整解决方案:

      xor  si, si          ;Same as "mov si,0"
    dis:
      mov  bl, elements[si]
      cmp  bl, '#'
      je   exit
      test bl, bl          ;Same as "cmp bl, 0"
      jns  IsPositive
      mov  dl, "-"         ;First display a minus sign
      mov  ah, 02h
      int  21h
      neg  bl              ;Turn the negative number into a positive number
    IsPositive:
      mov  dl, "0"
      add  dl, bl          ;Change the value [0,9] into character ["0","9"]
      mov  ah, 02h
      int  21h     
      inc  si 
      jmp  dis             ;Unconditionally jump back. Don't use "loop"
    exit:    
      mov  ax, 4C00h       ;Always use the full AX, the API defines it that way!
      int  21h
    

答案 1 :(得分:0)

这条指令

add dl, 48

dl(从elements数组设置)中存储的值加48,以将其映射到相应的ASCII数字(ASCII" 0" == 48)。

dl为负数时,结果将少于而不是48,并将映射到数字范围之外的ASCII字符。例如,处理-3时:

mov dl, -3
add dl, 48

将导致dl包含 45 。这映射到ASCII -(减号/破折号),这就是应该输出的内容。

假设elements中的每个值代表一个数字(0-9),您需要测试elements中的值是否为负值,取其绝对值,然后 add 指向48以获得正确的数字ASCII值。然后,您需要输出一个减号(ASCII 45),然后输出新计算的ASCII数字。

答案 2 :(得分:0)

由于您是初学者,我将“修复”您的代码以正确地执行错误的操作(根本不需要编写新代码来执行正确的操作,因为这会有太多更改)。

.model small
.stack 100h
    ; array terminator changed to -128, because signed bytes values can be -128 to +127
    ; so this new terminator allows for array with values -127 to +127
ARRAY_TERMINATOR    EQU     -128
    ; the old '#' is value 35, which makes weird possible range: [-128, +34] U [+36, +127]
.data
     elements db 2,-3,-4,5,2,9,ARRAY_TERMINATOR

.code
     mov ax, @data
     mov ds, ax  

     mov ax, 03h    ; ax = 3 <=> ah = 0 (set mode), al = 3 (text mode)
     int 10h        ; set default 80x25 text mode (clears screen)
     xor si,si      ; si = 0 (common x86 assembly idiom how to set zero)
        ; but it also destroy flags, so in certain cases the "mov r?,0" is needed.

display_loop:       ; use meaningful label names, when possible
        ; using short labels saves time while writing, but wastes time
        ; while reading + debugging, which you will do lot more often!

    ; load value first, so you can also compare it from register (faster/shorter)
     mov dl, [elements+si]  ; it doesn't hurt anything, when dl = -128 at end
        ; also I would rather put address label inside brackets, the "elements[]"
        ; way evokes false feeling, that it is array access from C. It is NOT.
        ; works like that for byte arrays, but already for WORD you need si*2!

    ; now it's possible to compare for terminator against register dl
     cmp dl, ARRAY_TERMINATOR
     je exit

     add dl, '0'    ; you can use ASCII '0' formatting of value 48 to better tell
        ; source reader, what you are trying to do, which is adding ASCII digit '0'
        ; try to write source to reflect your human intentions, you can write
        ; value 48 in many ways: 48, 30h, '0', 32+16, 3*16 ...
        ; All of them will compile into the same 48, but each tells different story
        ; to the reader of the source. +48 is arithmetic, +'0' is conversion to ASCII
     mov ah, 02h
     int 21h
        ; the code above will display correct digit only for values 0-9
        ; any other value will be mangled into some other ASCII character
        ; check ASCII table to get idea what happens for other values (10+48 = ':')

     inc si
     jmp display_loop   ; don't use loop without initializing "cx"
        ; and don't use "loop" either, do rather "dec cx" "jnz loop"
        ; "loop" instruction is artifically slowed down to support some legacy code
        ; Any way, in this case you don't want to loop per cx count, but until
        ; array terminator is hit, so use "jmp" instead to jump every time

    ; to fix the output the inner part of loop would have to:
    ;  display char '-' when value is negative (for example for value -123).
    ;  convert absolute value into digit characters in base-10 (decimal) formatting
    ;  which involves dividing the value by 10 until zero and remembering remainders
    ; For example |-123| = +123 => would produce remainders: 3, 2 and 1
    ; Then you add '0' to each remainder, and display them in reversed order.
    ; display ', ' characters (for start even after last number, when works, improve)
    ;  (logic to avoid last comma requires often some thought and more code
    ;  one usual way is to display first number without comma, and rest of array
    ;  starts by displaying comma, then number)

exit:
     mov ah, 04ch
     int 21h
end

(但至少我添加了一些“概述”,需要做些什么才能以预期的方式显示数字......无论如何,首先要注意我在第一个版本中更改的微小细节)