我是用emu8086
时间: 2025-06-06 16:29:21 浏览: 13
### emu8086中实现十进制转P进制的通用子程序
以下是在 emu8086 平台上设计的一个通用子程序,用于将用户输入的十进制数转换为指定的 P 进制数(P 可以为 2、8 或 16)。此子程序实现了完整的交互式功能,包括输入验证、基数选择以及最终的结果展示。
---
### 实现代码
```asm
.MODEL SMALL
.STACK 100H
.DATA
PROMPT DB 'Enter decimal number: $'
BASE_PROMPT DB 0DH, 0AH, 'Choose base (2/8/16): $'
ERROR_MSG DB 0DH, 0AH, 'Invalid input! Please try again.', 0DH, 0AH, '$'
RESULT_DB DB 16 DUP ('$')
NEWLINE DB 0DH, 0AH, '$'
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
; 显示提示信息并获取十进制数
LEA DX, PROMPT
MOV AH, 09H
INT 21H
CALL READ_DECIMAL_NUMBER
; 获取用户选择的目标基底
LEA DX, BASE_PROMPT
MOV AH, 09H
INT 21H
CALL CHOOSE_BASE
; 调用核心转换函数
CALL CONVERT_TO_P_BASE
EXIT_PROGRAM:
MOV AH, 4CH
INT 21H
MAIN ENDP
; ===========================
; 子程序:READ_DECIMAL_NUMBER
; 功能:从键盘读取一个有效的十进制数,并返回其值到 AX 中。
READ_DECIMAL_NUMBER PROC NEAR
XOR AX, AX ; 清零 AX 寄存器作为累加器
NEW_DIGIT:
MOV AH, 01H ; DOS API - 读取单个字符
INT 21H
CMP AL, 0DH ; 检测是否按下了回车键
JE DONE_READING
SUB AL, 30H ; 将 ASCII 数字转化为实际数值
JB INVALID_INPUT ; 如果结果小于 0,则非法输入
CMP AL, 9 ; 确保输入在合法范围内
JA INVALID_INPUT
PUSH AX ; 保存当前数字
MOV CX, 10 ; 设置倍率因子为 10
MUL CX ; 当前累积值 *= 10
POP AX ; 恢复本次输入的数字
ADD AX, AX ; 更新累积值
JMP NEW_DIGIT ; 继续读取下一位数字
INVALID_INPUT:
LEA DX, ERROR_MSG ; 显示错误消息
MOV AH, 09H
INT 21H
JMP MAIN ; 返回主菜单重新尝试
DONE_READING:
RET ; 返回主流程
READ_DECIMAL_NUMBER ENDP
; ===========================
; 子程序:CHOOSE_BASE
; 功能:让用户选择目标基底(2、8 或 16),并将结果存储到 BL 中。
CHOOSE_BASE PROC NEAR
MOV AH, 01H ; DOS API - 读取单个字符
INT 21H
CMP AL, '2' ; 是否选择了二进制?
JE SET_BASE_2
CMP AL, '8' ; 是否选择了八进制?
JE SET_BASE_8
CMP AL, '1' ; 特殊情况:判断是否输入了 '1' 后跟 '6'
JNE INVALID_SELECTION
MOV AH, 01H ; 再次读取下一个字符
INT 21H
CMP AL, '6' ; 是否确实选择了十六进制?
JNE INVALID_SELECTION
SET_BASE_16:
MOV BL, 16 ; 设定基础为 16
RET
SET_BASE_2:
MOV BL, 2 ; 设定基础为 2
RET
SET_BASE_8:
MOV BL, 8 ; 设定基础为 8
RET
INVALID_SELECTION:
LEA DX, ERROR_MSG ; 显示错误消息
MOV AH, 09H
INT 21H
JMP CHOOSE_BASE ; 请求重新输入
CHOOSE_BASE ENDP
; ===========================
; 子程序:CONVERT_TO_P_BASE
; 功能:将 AX 中的十进制数转换为目标基底 BL 的表示形式,并输出结果。
CONVERT_TO_P_BASE PROC NEAR
LEA SI, RESULT_DB + 15 ; 初始化指针指向结果数组末端
MOV DI, OFFSET RESULT_DB
MOV CL, BL ; 使用 CL 临时存储基底
CONVERSION_LOOP:
XOR DX, DX ; 清除 DX 寄存器准备做 DIV 操作
DIV BX ; AX / BL -> 商留在 AX,余数在 DX 中
ADD DL, 30H ; 将余数转化为 ASCII 形式
CMP DL, 3AH ; 如果超过 '9' 则需进一步处理字母 A-F
JL STORE_CHAR
ADD DL, 7 ; 调整偏移量使得 A-Z 符合 ASCII 表格位置
STORE_CHAR:
MOV [SI], DL ; 存储当前字符到结果数组中
DEC SI ; 移动指针向前一位
TEST AX, AX ; 测试商是否已经归零
JNZ CONVERSION_LOOP ; 若还有剩余部分未完成则重复循环
PRINT_RESULT:
CLD ; 方向标志清零以支持正向填充
LEA SI, RESULT_DB
FIND_START:
CMP BYTE PTR [SI], '$' ; 查找首个非空白字符的位置
JE INCREMENT_SI
INCREMENT_SI:
INC SI
LOOP FIND_START
DISPLAY_CHARS:
LODSB ; 逐字加载并显示字符直到遇到结束标记 $
CMP AL, '$'
JE FINISH_PRINTING
MOV DL, AL
MOV AH, 02H
INT 21H
JMP DISPLAY_CHARS
FINISH_PRINTING:
LEA DX, NEWLINE ; 打印新行
MOV AH, 09H
INT 21H
RET
CONVERT_TO_P_BASE ENDP
END MAIN
```
---
### 关键点解析
1. **输入验证机制**
- 在 `READ_DECIMAL_NUMBER` 子程序中加入了全面的输入校验逻辑,确保只有合法的十进制数字才能被接受[^1]。
2. **灵活的基数选择**
- 用户可以通过简单的按键组合轻松选择所需的转换基数(2、8 或 16)。对于十六进制的选择特别考虑到了可能误触的情况,增加了额外一层确认步骤[^2]。
3. **高效的转换算法**
- 主要采用反复除法的方式逐步提取每一位上的值,并即时将其映射成相应的 ASCII 字符以便后续打印输出。这种方法不仅直观而且易于理解与维护[^3]。
---
###
阅读全文
相关推荐



















