如何修复实模式汇编中的整数打印例程?
修复print_int例程的问题
问题根源分析
你的print_int存在多处栈操作和逻辑错误,导致输出乱码:
- 负数处理逻辑漏洞:非负数时未跳过
.negative代码块,错误修改栈数据 - 栈平衡破坏:
push si后未用pop si恢复,而是错误使用add sp,2,导致栈偏移和寄存器值丢失 - 缓冲区索引错误:打印时的地址计算错误,读取了栈中无关数据
- 循环计数错误:
.finish处的dec cx直接抵消有效位数,导致少打印或不打印
修复后的完整代码
; Displays a single character to the screen ; void putc(char %al) putc: mov ah, 0Eh int 10h ret ; Prints an integer to the screen ; void print_int(num %si, base %di) print_int: ; Initialize stack frame push bp mov bp, sp ; 校验基数范围 cmp di, 2 jl .return cmp di, 36 jg .return ; 保存寄存器 push bx push si push cx push dx ; 预留缓冲区和负数标记(1字节标记+64字节缓冲区) sub sp, BUFFER_SIZE + 1 mov byte [sp], 0 ; 负数标记初始为0 ; 处理负数(仅十进制) cmp si, 0 jge .loop cmp di, 10 jnz .loop ; 转为正数并标记负数 neg si mov byte [sp], 1 .loop: ; 计算余数和商 xor dx, dx mov ax, si div di ; 余数转字符并存入缓冲区(从缓冲区起始位置往后存) mov bx, sp add bx, 1 ; 跳过负数标记,指向缓冲区起始 add bx, cx ; cx是当前已存储的位数,从0开始 mov si, digits add si, dx mov al, [si] mov [bx], al ; 更新商和计数 mov si, ax inc cx ; 商不为0继续循环 cmp si, 0 jne .loop ; 打印负数符号(如果需要) cmp byte [sp], 1 jne .print_number mov al, '-' call putc .print_number: ; 从缓冲区末尾往前打印(因为余数是逆序存储的) mov bx, sp add bx, 1 add bx, cx dec bx ; 指向最后一个有效字符 .print_loop: cmp cx, 0 jle .end_print mov al, [bx] call putc dec bx dec cx jmp .print_loop .end_print: ; 清理栈并恢复寄存器 add sp, BUFFER_SIZE + 1 pop dx pop cx pop si pop bx .return: mov sp, bp pop bp ret digits: db "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" BUFFER_SIZE: equ 64
关键修复点说明
- 负数处理:新增
jge .loop跳过非负数的负数处理逻辑,仅在十进制且数字为负时才标记并取反 - 栈管理:明确预留缓冲区和标记的空间,操作栈时严格平衡,所有push的寄存器都对应pop
- 缓冲区存储:余数按逆序存入缓冲区(个位→十位→百位...),打印时从缓冲区末尾往前读取,保证输出顺序正确
- 循环计数:移除错误的
dec cx,直接用cx作为有效位数计数,确保所有数字位都被打印
测试验证
执行mov si, 5、mov di, 10、call print_int会输出5;mov si,17输出17;mov si,728输出728,符合预期。
内容的提问来源于stack exchange,提问作者Skeletonz33
相关产品推荐
相关产品推荐

