我几天前才开始学习汇编,看来我已经碰壁了。我有这个问题,我必须在汇编中编写一个程序,该程序接受整数输入(celcius)并将其转换为华氏度。
下面是我的代码:org 100h
jmp compare
var1 db 0
ans1 db ?
num1 db ?
num2 db ?
ex1 db ?
ex2 db ?
compare:
cmp var1,0
je start
jne move
move:
mov bl,var1
mov num1,bl
jmp digits
start:
mov ah,01h
int 21h
mov num1,al
cmp num1,0dh
jne digits
je convert
digits:
mov ah,01h
int 21h
cmp al,0dh
je revert
mov num2,al
jne proceed
proceed:
sub num1,48
mov cl,num1
mov al,10
imul cl
mov num1,al
sub num2,48
mov bl,num2
add num1,bl
mov bl,num1
mov var1,bl
jmp compare
revert:
cmp num2,0 ;also added this one too recently
jne c1
sub num1,48
c1:
mov bl,num1
mov var1,bl
jmp convert
convert:
mov cl, var1
mov al, 9
imul cl
mov cl, 5
idiv cl
add al, 32
mov ans1, al
mov bl,ans1
mov dl,0 ;i recently added this for convertion
mov al,ans1
mov bl,10
div bl
mov ex1,al
mov ex2,ah
adc ex1,48
adc ex2,48
print:
mov ah,02h
mov dl,10
int 21h
mov ah,02h
mov dl,13
int 21h
mov ah,02h
mov dl,ans1
int 21h
mov ah,02h ;print the converted values
mov dl,ex1
int 21h
mov ah,02h
mov dl,ex2
int 21h
ret
我以前输入15,结果是";",在ascii中是59。我需要帮助转换ascii;变成小数,当我输入更多大于2个数,表示溢出除法。我怎么解决这个问题?提前感谢!
编辑:我最近添加了转换代码。它现在可以工作了,但是如果我在输入中输入超过"20",输出就会出错。我使用了奥尔登的想法(非常感谢!)修改答案,并分别转换和打印它。我现在还在做这个,我还在挠头哈哈。这么多错误,哈哈。再次编辑:这太奇怪了。我的程序只能转换以5结尾的数字。它只能正确地转换5、15、25和35。这太奇怪了,其他的都是混乱的输出。有人能告诉我为什么会这样吗?
这比您想象的需要更多的工作。也有几种方法可以做到这一点。实际上,您需要的是获取每个小数点位置的值,然后打印result + 48
(48是ascii 0)。
例如,假设您的输入是15。你想打印一个1
和一个5
。你可以通过15 mod 10
得到5
。然后把15除以10。这个结果是1
。1 mod 10
结果为1
。您可以将这些值压入堆栈,直到value mod 10
等于零。我对我的组装生锈了,但这应该是一个功能模:
modTen:
push bp
mov bp, sp
push bx
mov ax, word [bp+4]
mov bx, ax
cwd
idiv 10
imul 10
sub bx, ax
mov ax, bx
pop bx
mov sp, bp
pop bp
ret
我使用GCC风格的调用者/被调用者假设,但你可以做任何你想做的。接下来,您需要使用以下步骤创建一个循环
push your parameter
call modTen
pop your parameter (or increment your SP)
push your result
increment a register to keep track of number of digits
divide your original value by 10
check if the result is zero.
If not, go back to the start of the loop.
If so, start popping your values and printing them.
更新:SP
代表堆栈指针。它指向存储在堆栈上的最后一个值。当您使用push
时,SP
将递减,并且引用寄存器中的值将压入到SP
指向的位置。pop
将将SP
指向的值从堆栈中弹出到寄存器中,然后增加SP
。(如果你想装填弹匣,你可以把子弹塞进去,然后弹出来。它是一个先入后出的结构或堆栈)。
BP
代表基指针,指向标记当前函数正在使用的堆栈起点的位置。例如,在modTen
中,当调用函数时,它保存旧函数的基指针,将当前堆栈指针移动到基指针中,然后将其用作附近所有其他值(如函数的参数)的引用。这样做的预期目的是,当函数执行时,它需要堆栈空间来存储变量。当你的堆栈指针移动时,你失去了东西所在的位置(理论上,尽管你可以完全没有基指针)。
当用汇编语言编写时,将代码分成函数并设置一些假设是很方便的,这样当其他人使用你的代码时,或者你在将来的某个时间回去重用它时,你就不需要重新阅读所有的代码来让它工作。汇编程序通常很难理解,因为它不清楚作者想要它做什么。8086汇编的约定是,函数的参数以相反的顺序压入堆栈。然后使用call
跳转到该函数。Call将下一条指令的位置(返回地址)压入堆栈。然后被调用函数(或被调用函数)通过压入保存前一个函数的基指针。然后将SP
复制到BP
中,使用BP
的值来引用变量。在使用寄存器之前,被调用者还将保存除AX
之外的所有已使用的寄存器,然后在使用它们之后恢复它们。AX
用于返回值,因此调用者必须在调用之前保存其中的内容(如果您想保留它)。当函数执行时,堆栈看起来是这样的。
....
function's second argument -> XXXX
function's first argument -> XXXX
return address -> XXXX
BP points here -> XXXX
Also, saved last BP
some variable -> XXXX
....
SP points here -> XXXX
and another variable
....
很明显,你对x86架构不是很熟悉,这在编写x86汇编程序时非常重要。例如,您可能知道,也可能不知道x86使用段和指针寄存器来计算地址。随着您对x86汇编的经验越来越丰富,这可能会使您陷入困境。我强烈建议您查找有关8086体系结构详细概述的书籍或在线资源。如果你这样做了,你就会做好充分的准备,长出你的胡须,像1980年那样编写代码。
同样,如果你正在使用某种linux或unix环境,你已经有了世界上最好的汇编学习资源。使用objdump -S a.out
查看编译后的可执行文件的程序集。如果你用-g编译,那么它会告诉你哪段代码与哪条汇编指令对应。非常整洁。(这是假设您正在使用GCC)。而且,我从来没有使用过它,但是这个用户有一个gcc补丁的源代码,可以编译8086兼容的16位指令。