如何在x86 Linux NASM汇编中实现两个不同长度数字的加法
汇编不同长度数字加法问题修复方案
我是汇编开发新手,目前在实现不同长度数字的基础计算时遇到了问题。我编写的加法代码仅支持3位及以内的等长数字加法运算,例如123+123可正常输出246,但计算12+123时会错误输出253。请问该如何修改代码使其支持不同长度数字的加法运算?
错误根源
- 输入的数字是高位在前、低位在后的字符串格式,原代码直接使用同一个偏移量读取两个数字的位,没有按最低位对齐;数字长度不一致时,短数字的高位会读取到缓冲区的换行符或垃圾值,导致计算错误
- 固定使用第二个数字的长度作为循环次数,没有取两个数字的最大长度作为循环边界
sys_read返回的长度包含末尾的换行符,原代码没有正确剔除换行符计算有效数字长度- 原代码最后缺少系统退出调用,执行结束会触发段错误
修复思路
- 读取输入后先减去1,得到剔除换行符的有效数字长度
- 取两个数字长度的最大值作为循环次数
- 给两个数字分别设置独立的索引指针,初始指向各自的最低位(字符串最后一个有效字符),超出自身长度的高位统一补0计算
- 循环结束后检查进位标志,有进位则补充到结果的最高位
- 补充系统退出逻辑避免崩溃
完整修复后代码
sys_exit equ 1 sys_read equ 3 sys_write equ 4 stdin equ 0 stdout equ 1 section .data newLine db 10 cquestion db 'Enter a number: ', 0xa cqLen equ $ - cquestion answer db 'Your answer is: ' aLen equ $ - answer section .bss number1 resb 4 number2 resb 4 number1Len resd 1 number2Len resd 1 answ resb 8 %macro write_string 2 mov eax, 4 mov ebx, 1 mov ecx, %1 mov edx, %2 int 0x80 %endmacro section .text global _start _start: ; 读取第一个数字 write_string cquestion, cqLen mov eax, sys_read mov ebx, stdin mov ecx, number1 mov edx, 4 int 0x80 dec eax ; 剔除换行符长度 mov [number1Len], eax ; 读取第二个数字 write_string cquestion, cqLen mov eax, sys_read mov ebx, stdin mov ecx, number2 mov edx, 4 int 0x80 dec eax ; 剔除换行符长度 mov [number2Len], eax write_string answer, aLen ; 取两个数字的最大长度作为循环次数 mov ecx, [number1Len] cmp ecx, [number2Len] jge .set_cycle_len mov ecx, [number2Len] .set_cycle_len: push ecx ; 暂存长度用于后续输出 ; 初始化各数字的索引指针,指向最低位 mov esi, [number1Len] dec esi mov edi, [number2Len] dec edi mov edx, ecx dec edx ; 结果缓冲区的索引指针 clc ; 清空进位标志 .add_loop: ; 读取第一个数字的当前位,超出长度则补0 mov al, 0 cmp esi, 0 jl .get_num2 mov al, [number1 + esi] sub al, 30h ; ASCII转数值 .get_num2: ; 读取第二个数字的当前位,超出长度则补0 mov bl, 0 cmp edi, 0 jl .do_add mov bl, [number2 + edi] sub bl, 30h ; ASCII转数值 .do_add: adc al, bl aaa ; 非压缩BCD调整 pushf ; 保存进位标志避免后续操作修改 or al, 30h ; 数值转回ASCII popf ; 恢复进位标志 mov [answ + edx], al dec esi dec edi dec edx loop .add_loop ; 处理最后的进位 jnc .output_ans mov byte [answ + edx], '1' dec edx .output_ans: ; 计算结果实际长度 pop ecx cmp edx, 0 jge .add_carry_len jmp .write_result .add_carry_len: inc ecx .write_result: mov eax, sys_write mov ebx, stdout lea ecx, [answ + edx + 1] mov edx, ecx int 0x80 ; 输出换行 mov eax, sys_write mov ebx, stdout mov ecx, newLine mov edx, 1 int 0x80 ; 正常退出 mov eax, sys_exit mov ebx, 0 int 0x80
说明
- 原代码中
pushf、popf的作用是保存进位标志,避免or al,30h操作修改标志位导致后续adc计算错误 aaa是非压缩BCD调整指令,用于确保加法后的低4位是0~9的有效数字- 修复后支持3位及以内任意长度数字的加法,测试12+123可正常输出135
内容的提问来源于stack exchange,提问作者Lauri
相关产品推荐
相关产品推荐

