【问题标题】:Unable to display negative numbers using array in the following 8086 assembly code无法在以下 8086 汇编代码中使用数组显示负数
【发布时间】:2017-07-08 15:13:44
【问题描述】:

我要做什么

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

有什么问题

我无法打印负数。

输入:

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

注意:我完全是汇编初学者。

【问题讨论】:

  • 唉 DOS 缺少打印整数的功能,因此您必须自己通过打印单个字符来实现它。你是汇编语言的初学者,这很公平。我的建议是,假设您首先以您更熟悉的语言实现此功能,尽管仅使用基本的putchar 功能并且没有库支持功能。这应该作为实现等效程序集的一个很好的起点和参考。

标签: assembly x86-16


【解决方案1】:

你的程序有两个主要问题:

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

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

这是一个完整的解决方案,其中包含其他重要的 cmets:

  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

【讨论】:

  • 今天有人在编写循环任务时自动使用LOOP 指令遇到了同样的问题。实在是太像了!
【解决方案2】:

由于您是完全的初学者,我只会“修复”您的代码以正确地执行错误的操作(根本不会费心编写新代码来执行正确的操作,因为无论如何更改都会太多)。

.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

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

【讨论】:

    【解决方案3】:

    这条指令

    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中的值是否为负,取其绝对值,然后添加 48 以得出该数字的正确 ASCII 值。然后你需要输出一个减号(ASCII 45),后跟新计算的 ASCII 数字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-15
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      相关资源
      最近更新 更多