x86汇编实现计算器时除法功能输出异常问题求助
基础计算器除法功能异常修复
问题现象
选择除法(输入4)后,输入被除数20和除数5,程序输出0/20->20,不符合预期的20/5->4。
问题根源
除法运算逻辑错误:
- 未将正确的被除数放入
rax寄存器就执行cqo和idiv,导致实际计算的是除数除以被除数,得到商0。 - 除数为0的判断逻辑错误,当前代码检查的是被除数(
r15)而非除数是否为0。
- 未将正确的被除数放入
打印参数顺序完全错误:
格式串dividestr定义为"%d / %d -> %d\n",对应顺序是「被除数 / 除数 -> 商」,但当前printintdiv传递的参数是「商 / 被除数 -> 除数」,完全匹配错位。
修复方案
修正除法运算流程:
- 将被除数(
r14)移入rax,用cqo扩展符号位到rdx,准备有符号除法。 - 先保存除数(原
rax值)到临时寄存器,检查除数是否为0,再执行idiv完成除法。
- 将被除数(
修正打印参数顺序:
按照格式串要求,依次传递被除数、除数、商到printf的对应参数寄存器。修正除零判断逻辑:
检查除数而非被除数是否为0,除零场景下正确传递被除数和0作为除数到打印函数。
修正后的完整代码
# CPSC 2500 Winter 2023 # Name: # Date: # Compile on Linux using: gcc -g -fno-pie -no-pie ./calc.s -o calc .bss # block starting symbol, contains allocated but not yet initialized memory num: # num will hold a 64 bit integer provided by the user .skip 8 .data addstr: # C-style formatting for calling printf() .asciz "%d + %d -> %d\n" minusstr: # C-style formatting for calling printf() .asciz "%d - %d -> %d\n" mutiplystr: # C-style formatting for calling printf() .asciz "%d * %d -> %d\n" dividestr: # C-style formatting for calling printf() .asciz "%d / %d -> %d\n" .text .global main getint: # get integer from user movq $0, %rax movq $0, %rdi movq $num, %rsi movq $8, %rdx syscall # get user input from STDIN movq $num, %rdi call atoi # convert user input from string to integer ret printint: # print result of addition mov $addstr, %rdi mov %r14, %rsi mov %rax, %rdx mov %r15, %rcx xor %rax, %rax call printf ret printintminus: # print result of subtraction mov $minusstr, %rdi mov %r14, %rsi mov %rax, %rdx mov %r15, %rcx xor %rax, %rax call printf ret printinttimes: # print result of multiplication mov $mutiplystr, %rdi mov %r14, %rsi mov %rax, %rdx mov %r15, %rcx xor %rax, %rax call printf ret printintdiv: # print result of division mov $dividestr, %rdi # Format string mov %r14, %rsi # 被除数 mov %r12, %rdx # 除数 mov %rax, %rcx # 商 xor %rax, %rax call printf ret end: # terminate program mov $60, %rax xor %rdi, %rdi syscall main: call getint mov %rax, %r13 cmpq $-1, %r13 je end call getint mov %rax, %r15 call getint mov %r15, %r14 cmpq $1, %r13 je addtwonums cmpq $2, %r13 je subtwonums cmpq $3, %r13 je mutiplytwonums cmpq $4, %r13 je dividetwonums jmp main addtwonums: add %rax, %r15 call printint jmp main subtwonums: sub %rax, %r15 call printintminus jmp main mutiplytwonums: imul %rax, %r15 call printinttimes jmp main dividetwonums: mov %rax, %r12 # 保存除数到r12 mov %r14, %rax # 将被除数放入rax cqo # 扩展符号位到rdx,准备有符号除法 cmpq $0, %r12 # 检查除数是否为0 je divisionbyzero idiv %r12 # 执行除法:rdx:rax / r12,商存rax,余数存rdx call printintdiv jmp main divisionbyzero: mov $dividestr, %rdi mov %r14, %rsi # 被除数 mov $0, %rdx # 除数(0) mov $0, %rcx # 商设为0 xor %rax, %rax call printf jmp main
内容的提问来源于stack exchange,提问作者YTN1112
相关产品推荐
相关产品推荐

