Unable to display negative numbers using array in the following 8086 assembly code

穿精又带淫゛_ 提交于 2019-12-11 06:02:49

问题


What i am trying to do

I am trying to print a series of negative and positive numbers using array.

What is the problem

I am not able to print negative numbers.

Input:

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

Output:

2-,529

My 8086 Assembly Code:

.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

Note: I am a complete beginner in assembly.


回答1:


Your program has 2 major problems:

  1. You're using the loop instruction without having initialized the counter register CX beforehand! Luckily your code has an extra terminating condition on top of the CX register probably being zero to start with. And then to think that you don't even need this instruction in this program.

  2. You never test if the number that you read from the array is positive or negative.

Here's a complete solution with additional important comments:

  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



回答2:


As you are complete beginner, I will just "fix" your code to do the wrong thing correctly (not bothering to write new code doing the correct thing at all, as that would be too many changes any way).

.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

(But at least I added some "overview", what would have to be done to display the numbers in expected way... anyway, pay attention first to the tiny details, which I changed in your first version)




回答3:


This instruction

add dl, 48

adds 48 to the value stored in dl (set from the elements array), to map it onto the corresponding ASCII digit (ASCII "0" == 48).

When dl is negative the result will be less than 48 and would map onto an ASCII character outside of the digit range. For example, when processing -3:

mov dl, -3
add dl, 48

will result in dl containing 45. This maps onto ASCII - (minus/dash), so that is what should be output.

Assuming that each value in elements represents a single digit (0-9) you need to test whether the value in elements is negative, take its absolute value, then add that to 48 to arrive at the correct ASCII value for the digit. Then you need to output a minus character (ASCII 45) followed by the newly calculated ASCII digit.



来源:https://stackoverflow.com/questions/42325964/unable-to-display-negative-numbers-using-array-in-the-following-8086-assembly-co

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!