基于ASM x86(Intel语法)的计算器,为什么减法不起作用?
我在学习x86汇编(Intel语法),在FreeDOS下把一个简单的计算器写成一个.COM程序。程序从键盘读取两个数字和一个运算符,然后执行运算。
加法工作正常,但减法给出错误的结果(表现得像加法,或得到错误的值)。
示例: 输入:2-1= 期望输出:1 实际输出:3(或错误的数值)
程序流程:
- BX初始化为5000
- 每次按下一个键通过
int 16h读取 - 输入通过
grd例程存储到内存中 - 为了简化内存处理,我将值存放在固定的内存地址:
5000 -> 第一个操作数
5002 -> 运算符
5004 -> 第二个操作数 - 当BX到达5004时,执行跳转到
cn - 在
cn中,将操作数装入CL与 DL - 从内存中读取运算符并与 '+'(43)和 '-'(45)进行比较
- 根据结果跳转到加法或减法
- 通过int 10h打印结果
限制与设计取舍:
- 仅支持单个数字操作数(0–9)
- 仅实现了加法与减法
- 输入逐字符读取
- 未进行严格的输入验证
- 结果以单个数字输出
我在每次输入后将BX增加2。选择这种做法,是为了避免数值重叠,并在学习底层内存管理时让内存布局更易于理解。
我怀疑问题可能与ASCII值的处理方式、或运算符的存放方式有关。
下面是代码:
org 100h
mov bx, 5000
cun:
xor ah, ah
int 16h
call grd
add al, 48
cmp al, 81
je fin
mov ah, 0Eh
int 10h
jmp cun
cn:
pop bx
mov bx, 5000
mov cl, [bx]
add bx, 4
mov dl, [bx]
sub bx, 2
cmp byte [bx], 43
je sum
cmp byte [bx], 45
je res
sum:
add cl, dl
mov ah, 0Eh
mov al, cl
add al, 48
int 10h
jmp cun
res:
sub cl, dl
mov ah, 0Eh
mov al, cl
add al, 48
int 10h
jmp cun
grd:
sub al, 48
mov [bx], al
cmp bx, 5004
jge cn
add bx, 2
ret
fin:
int 20h
解决方案
看到你能对程序做出如此详细的解释,我感到很欣慰;但同时你的源代码完全缺少(尾部)注释!这绝对是需要改进的地方……
你的grd子程序有点特殊!
你对每个输入的字符代码都减去48,无论它是否代表一个数字;并且在收到三个输入后就不再返回。后者虽然在某些情况下能工作,但在学习语言时你大概不应该这么做。
对每个输入都减去48也是导致程序结束测试(add al, 48 cmp al, 81)显得尴尬的原因之一。顺便说一句,你可以把这写成 cmp al, 'Q',要清晰得多。
我不会使用你写的那种子例程,而是把所有内容放在一个直接的循环里:
org 100h
mov di, 5000 ; Teletype uses BH (BX) for its display page
cun:
xor ah, ah ; BIOS.ReadKeystroke
int 16h ; -> AX
cmp al, 'Q' ; Test before anything else (no echo needed)
je fin
mov bx, 0007h ; Teletype uses BH (BX) for its display page
mov ah, 0Eh ; Do the echo BEFORE you convert anything!
int 10h
sub al, '0' ; Convert AND check for decimal digit
cmp al, 10
jb Gotit
add al, '0' ; Restore original ASCII
Gotit:
stosb ; AL={[0,9],"+","-"}
cmp di, 5003
jb cun
mov bx, 5000
mov cl, [bx] ; First operand
mov dl, [bx+2] ; Second operand
cmp byte [bx+1], "+"
je sum
cmp byte [bx+1], "-"
je res
jmp cun ; Redo
- 如果运算符是除了 "+" 或 "-" 之外的任意字符,你不应该在sum中继续执行,而应该从头重新开始(或退出)。
- 请注意:我把存储空间缩减为每项数据一个字节。
- 请注意,你并不局限于仅使用
[bx]。在NASM中你还可以像在[bx+1]那样添加偏移量。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。