MASM打印质数问题:移除USES伪指令后出现无限循环求助
汇编质数检测过程移除USES伪指令后无限循环问题解决
问题背景
需求是按顺序打印x个质数,编写了isPrime过程判断质数,但要求不能使用USES伪指令。移除USES后程序出现无限循环,寻求解决方案。
原带USES伪指令的isPrime过程
isPrime PROC USES ECX EBX ; 检测一个数是否为质数,是则返回布尔值1,否则返回0 ; 输入:EAX中存放待检测的数 ; 输出:EAX中返回布尔值(0或1) ; 前置条件:EAX的值在[1..200]范围内 ; 修改的寄存器:EAX, EBX, ECX, EDX ;------------------------------------------------------------------------- mov ecx,eax ; 将待检测数p复制到ECX mov esi, 2 ; 初始化循环变量i=2 startLoop: cmp esi,ecx jge PrimeNum ; 若i>=p,说明是质数,跳转到PrimeNum mov edx,0 mov eax,ecx div esi ; 计算p/i,EAX=p/i,EDX=p%i cmp edx, 0 je NotPrime ; 若余数为0,说明不是质数 inc esi ; 否则i自增,继续检测 jmp startLoop PrimeNum: mov eax, TRUE ; 是质数,返回1 ret NotPrime: mov eax, FALSE ; 不是质数,返回0 ret isPrime ENDP
移除USES伪指令后的代码(存在问题)
mov ecx,eax ; 将待检测数p复制到ECX mov try2, 2 ; 初始化循环变量i=2 startLoop: cmp try2,ecx jge PrimeNum ; 若i>=p,说明是质数,跳转到PrimeNum mov edx,0 mov eax,ecx div try2 ; 计算p/i,EAX=p/i,EDX=p%i cmp edx, 0 je NotPrime ; 若余数为0,说明不是质数 inc try2 ; 否则i自增,继续检测 jmp startLoop PrimeNum: mov eax, TRUE ; 是质数,返回1 ret NotPrime: mov eax, FALSE ; 不是质数,返回0 ret
问题原因
- 寄存器上下文未保存:
USES伪指令的作用是自动在过程开头push指定寄存器、结尾pop恢复其状态。原代码中USES ECX EBX会自动保存ECX和EBX,移除后未手动保存被过程修改的ECX,导致调用者(比如主程序)的ECX值被覆盖。若主程序用ECX控制质数打印数量,会直接破坏循环逻辑,引发无限循环。 - 过程定义缺失:移除USES后的代码丢失了
isPrime PROC和isPrime ENDP的过程边界定义,导致ret指令无法正确找到返回地址,可能引发执行流程混乱。 - 全局变量依赖:改用全局变量
try2存储循环变量,虽然本身不会直接导致无限循环,但全局变量容易引发上下文污染,不是汇编的最佳实践。
修复后的代码
方案1:保留全局变量,手动保存寄存器
isPrime PROC ; 检测一个数是否为质数,是则返回1,否则返回0 ; 输入:EAX中存放待检测的数 ; 输出:EAX中返回布尔值(0或1) ; 前置条件:EAX的值在[1..200]范围内 ; 修改的寄存器:EAX, ECX, EDX push ecx ; 手动保存调用者的ECX寄存器 mov ecx, eax ; 将待检测数p存入ECX mov try2, 2 ; 初始化循环变量i=2 startLoop: cmp try2, ecx jge PrimeNum ; 若i>=p,判定为质数 mov edx, 0 mov eax, ecx div try2 ; 计算p/i,取余数EDX cmp edx, 0 je NotPrime ; 余数为0则不是质数 inc try2 ; i自增,继续循环 jmp startLoop PrimeNum: mov eax, TRUE ; 返回1(质数) pop ecx ; 恢复调用者的ECX寄存器 ret NotPrime: mov eax, FALSE ; 返回0(非质数) pop ecx ; 恢复调用者的ECX寄存器 ret isPrime ENDP
方案2:改用寄存器存储循环变量(推荐)
避免全局变量,改用ESI寄存器存储循环变量,同时手动保存所有被修改的寄存器:
isPrime PROC ; 检测一个数是否为质数,是则返回1,否则返回0 ; 输入:EAX中存放待检测的数 ; 输出:EAX中返回布尔值(0或1) ; 前置条件:EAX的值在[1..200]范围内 ; 修改的寄存器:EAX, ECX, EDX, ESI push ecx ; 保存调用者的ECX push esi ; 保存调用者的ESI mov ecx, eax ; 待检测数p存入ECX mov esi, 2 ; 初始化循环变量i=2 startLoop: cmp esi, ecx jge PrimeNum ; i>=p则为质数 mov edx, 0 mov eax, ecx div esi ; 计算p/i,取余数EDX cmp edx, 0 je NotPrime ; 余数为0则非质数 inc esi ; i自增 jmp startLoop PrimeNum: mov eax, TRUE ; 返回1 pop esi ; 恢复ESI pop ecx ; 恢复ECX ret NotPrime: mov eax, FALSE ; 返回0 pop esi ; 恢复ESI pop ecx ; 恢复ECX ret isPrime ENDP
关键说明
- 手动保存寄存器时,要确保
push和pop的顺序相反(先进后出),保证寄存器状态正确恢复。 - 过程必须保留
PROC和ENDP定义,明确过程的起始和结束边界,确保ret指令能正确返回。
内容的提问来源于stack exchange,提问作者dami1025
相关产品推荐
相关产品推荐

