Assembly 组装8086。从标准输入中读取数个数字,以2为基数。在屏幕上以10为基数打印这些数字

Assembly 组装8086。从标准输入中读取数个数字,以2为基数。在屏幕上以10为基数打印这些数字,assembly,x86-16,Assembly,X86 16,所以,我必须把以2为基数的数字转换成以10为基数的数字,我不知道该怎么做。这就是我的程序现在的样子,但我不确定我现在得到的是否能正常工作。转换部分真的让我很为难,但可以肯定的是,我的代码中有很多错误,所以任何帮助都将不胜感激 assume cs:code, ds:data data segment msg db 'Give numbers:$' numbers LABEL BYTE max_size DB 100 numbers_len DB ? number D

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

   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

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

下面是从基数为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
是字符串中的当前位置,从零开始

将值转换为base-10的代码使用除法将存储在寄存器中的“本机”base-2值转换为该值的连续base-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

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

好的,您遇到了什么问题?您已经大致说明了所需的行为和输出,但是您没有提到所提供的输入,也没有提到所观察到的输出。求求你,求求你-不要说“它不工作了”。您是否已使用调试器逐步完成了代码?具体来说,您需要帮助的是什么?在我给出数字后,它进入了一个无限循环TurboDebugger始终是DOS的一个好调试器。无论如何,请查看
检查:
标签后面的代码。如果数字太小,请勾掉。如果数字太大,请勾掉。如果数字正好(0或1),则jmp转换为
。在这一点上,如果您从未使用jmp进行
转换,那么您就可以直接返回到您应该到达的位置。
Hmmmmm?!您的另一个问题是,您的循环计数器,
CX
int21h
期间未被触动-它不是,您应该先推它,然后再弹出它。接下来,在循环中弹出
dx
。它被推过这么多次吗?@enhzflep我看到int 21h/02h 21h/09h和21h/0ah。哪一个破坏CX、CL或CH?“据我所知,这些特殊的中断并没有破坏CX。”迈克尔·佩奇——的确如此。进一步检查发现,我没有正确地记住这一点:垂下头去用ECC搜索神经元:
addax,1
将保存一个寄存器;在循环之前使用
mov-dx,1
对我来说似乎是混淆。(如果您希望使用较小的代码大小来避免立即生效,请使用
inc ax
)。哦,我看到你是从LSB(字符串的结尾)而不是开始循环的。您可以
shl ax,1
在正在累积的数字的底部打开一个新的空格。此外,
cmp dl,[di]
(dl中有'0')/
adc ax,ax
将在
1
位(从'0'-'1'产生借位)或
0
位(从它们相等的位置)中移动,因此您可以避免单独的
shl ax,1