【问题标题】:Assembly 8086. Read from the standard input several numbers, in base 2. Print on the screen these numbers in base 10汇编 8086。从标准输入中读取几个以 2 为底的数字。在屏幕上打印以 10 为底的这些数字
【发布时间】:2018-10-14 12:12:43
【问题描述】:

所以,我必须将数字从以 10 为底的 2 转换,我不知道该怎么做。这就是我的程序现在的样子,但我不确定到目前为止我得到的是否能正常工作.转换部分真的让我很难过,但我的代码肯定有很多错误,所以任何帮助都将不胜感激。

   assume cs:code, ds:data

data segment
msg db 'Give numbers:$'
numbers LABEL BYTE
    max_size DB 100
    numbers_len DB ?
    number DB 100 dup (?)
ten db 10
errm db 'Numbers not in binary.$'
data ends
code segment
start:

mov ax,data
mov ds,ax

mov ah,09h
mov dx,offset msg
int 21h

mov AH,0Ah
mov DX,offset numbers
int 21h

mov CL,numbers_len
mov CH,0
mov SI,0    
repeat:
    mov AL,number[SI]
    cmp AL,' '
    je conversion

    check:
    cmp AL,'0'
    jb erro
    cmp AL,'1'
    ja erro

    jmp conversion
    continue:
    inc SI
    dec cx
    jcxz print 
    jmp repeat


conversion:

    jmp continue

print:
    pop dx
    add dl,'0'
    mov ah,02h
    int 21h
    loop print  
erro:
    mov ah,09h
    mov dx,offset errm
    int 21h

mov ax,4c00h
int 21h

code ends
end start

【问题讨论】:

  • 好的,您遇到了什么问题?您已经大致说明了所需的行为和输出,但您没有提及提供的输入,也没有提及观察到的输出。拜托,拜托 - 不要说“它不工作”。您是否使用调试器单步执行了代码?具体来说,您需要哪些帮助?
  • 输入数字后进入无限循环
  • TurboDebugger 一直是 DOS 的好调试器。不管怎样,看看check: 标签后面的代码。如果数字太小,切掉。如果数字太大,请切掉。如果数字正好(0 或 1),则 jmp 到 conversion。此时,如果您从未跳转到conversion. 嗯嗯?!您的其他问题之一是认为您的循环计数器CXint 21h 期间未被触及 - 它不是,您应该先推它然后再弹出它。接下来,您将循环弹出dx。先推送这么多次了吗?
  • @enhzflep 我看到 int 21h/02h 21h/09h 和 21h/0ah。哪一个会破坏 CX、CL 或 CH?据我所知,这些特殊的中断不会破坏 CX
  • @MichaelPetch - 确实如此。进一步检查发现我记错了。 :用ECC垂头寻找神经元:

标签: assembly x86-16


【解决方案1】:

首先,不能直接执行base-2到base-10的转换:你必须将base-2表示转换为寄存器中的实际值,然后将其转换为base-10。这是因为这些碱基彼此不相关,例如没有办法通过对 2 进行整数幂来获得 10。

这是从 base-2 字符串转换为数字的代码。不执行错误检查,每个不是1 的字符都被简单地视为0

; input : bx - the starting address of the string, cx - its length
; output : ax - contents of the string interpreted as base-2
from_bin:
  mov di, bx
  add di, cx
  sub di, 1
  xor ax, ax
  mov dx, 1

.loop:
  cmp di, bx
  jb .end

  cmp byte [di], '1'
  jne .loop_next

  add ax, dx

.loop_next:
  shl dx, 1
  sub di, 1
  jmp .loop

.end:
  ret

如您所见,如果在当前位置有1,则代码通过添加dx 来构建ax 中的返回值。 dx 对应循环的每次迭代中 2^n 的值,其中n 是字符串中的当前位置,从零开始。

将值转换为以 10 为底的代码使用除法将存储在寄存器中的“本机”以 2 为底的值转换为该值的连续以 10 为底的数字。

; input : ax - the number to convert
; di - the last writable address of the output buffer
; output : di - the address of the last written character
; destroys bx, cx, dx
to_dec:
  mov cx, 10

.loop:
  xor dx, dx
  div cx

  mov bx, dx
  or bl, '0'
  mov [di], bl
  test ax, ax
  jz .end

  sub di, 1
  jmp to_dec

.end:
  ret

转换是“向后”完成的:它从最低位置开始,只要除法的结果不为零,它就会一直向上 - 这意味着还有更多的东西要转换。这也是为什么函数需要获取缓冲区的最后一个可写地址而不是其开头的原因。

【讨论】:

  • add ax, 1 会保存一个寄存器;在循环之前使用mov dx, 1 对我来说似乎是一种混淆。 (如果您想要避免立即数的较小代码大小,请使用inc ax)。哦,我看到你是从 LSB(字符串的结尾)而不是开头循环的。你可以shl ax,1在你积累的数字的底部开辟一个新的空间。
  • 另外,cmp dl, [di](在 dl 中带有 '0')/adc ax, ax 将移入 1 位(从 '0'-'1' 产生借位)或 @987654337 @bit(从它们相等),所以你可以避免单独的shl ax,1
猜你喜欢
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
相关资源
最近更新 更多