You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

汇编实现贪吃蛇游戏栈操作异常及运行问题求助

汇编贪吃蛇项目栈操作相关问题及修复方案

问题描述

在课堂上编写了一款贪吃蛇游戏,此前学习了栈段(Stack Segment)的push、pop操作以及黑盒封装知识,尝试将栈操作应用到贪吃蛇项目中后,代码长度增加且程序无法正常运行,需要定位问题。
具体疑问:

  • 老师提到任何proc都要以push开头、pop结尾,如果在当前proc内部调用其他proc,是需要遵循同样的入栈出栈规则,还是要先完成出栈再调用下一个proc?
  • 如何确定具体是哪部分代码出错?

当前异常表现:程序在DOSBOX中编译时提示0警告0错误,但运行时贪吃蛇无法移动,随机生成的道具也不显示。

问题代码

MODEL small
         STACK 100h
         DATASEG
snake_length dw 3
object dw ?
Clock equ es:6Ch
message db 'game over, do you want to play again$'
; --------------------------
CODESEG
proc cleanscreen
    push cx
    push bx
    push ax
    xor ax,ax
    mov cx,4000d
    mov bx,0
    clean:
    mov [es:bx],al
    inc bx
    loop clean
    pop ax
    pop bx
    pop cx
    ret
    endp cleanscreen
    
proc playgame ;starts the game
push ax
mov ax,0b800h
mov es,ax
pop ax
call cleanscreen
push bx
push dx
mov dh, 200
mov dl, '*'
xor bx,bx
mov di,2000d
mov [es:di],dx
mov [es:di-2],dx
mov [es:di-4],dx
mov [word ptr bx], 1996d
mov [word ptr bx+1], 1998d
mov [word ptr bx+2], di
pop dx
pop bx
call random
call movement
ret
endp playgame

proc movement
mov ah,1
int 16h
jnz skip
mov ah,0
int 16h
skip:
cmp al, 'w'
je wp
cmp al, 'a'
je ap
cmp al, 'd'
je dpointer
cmp al, 's'
je  spo
cmp al, 'q'
je endgame
call movement

wp:
sub di,160d
jmp update
spo:
add di,  160d
jmp update
dpointer:
add di,2d
jmp update
ap:
sub di,2d
update:
call bounderies
ret
endp movement

proc bounderies
push ax
push dx
push bx
cmp di,160d 
jb endgame
cmp di, 38940
ja endgame
mov ax,di
mov bl, 160d
div bl
cmp ah,0
je endgame
inc ax
mov ax,di
div bl
cmp ah,0
je endgame
pop bx 
pop dx
pop ax
call update_snake
ret
endp bounderies

proc update_snake
push bx
push si
push cx
mov cx, offset snake_length
xor bx,bx
xor ch,ch
mov si,[bx]
mov [es:si], ch
transition:
mov si,[bx+1]
mov [bx],si
loop transition
mov [bx], di
pop cx
pop si
pop bx
call delay
ret
endp update_snake

proc delay
push cx
push bx
    mov cx, 0FFFFh  
    lopa:
        mov bx, 50
        lopb:
            dec bx
            cmp bx, 0
            jnz lopb
    loop lopa
    ret
    pop bx
    pop cx
    call check_if_eaten
endp delay

proc endgame
ret
endp endgame

proc check_if_eaten
cmp di, [object]
jne restfunc
call random
restfunc:
call movement
ret
endp check_if_eaten

proc random
push ax
push bx
mov ax, [Clock] ; read timer counter
mov ah, [byte cs:bx] ; read one byte from memory
xor al, ah ; xor memory and counter
and al, 00001111b ; leave result between 0-15
sal al,1
mov [byte ptr object], al
pop bx
pop ax
ret 
endp random

start:
    mov ax, @data
    mov ds, ax
    call playgame
exit:
    mov ax, 4c00h
    int 21h
END start 

问题解答

栈规则说明

你提到的proc入栈出栈规则本质是寄存器保护约定:每个proc在入口处把自己会修改的寄存器push入栈,在返回(ret)之前按相反顺序pop恢复,和proc内部是否调用其他proc无关。内部调用其他proc时,被调用的proc自己会负责保护它用到的寄存器,不需要先把当前proc的栈pop完再调用,只要保证当前proc自己的push和pop配对、在ret前恢复所有入口时保存的寄存器即可。

代码具体错误点

  1. delay过程栈不平衡+逻辑截断
    delay过程中ret写在了pop操作和call check_if_eaten之前,导致栈中残留了push的cx和bx,且后续的道具检测、移动逻辑永远不会执行,程序运行流程完全错乱。
    修复方案:把ret移到过程末尾:
proc delay
push cx
push bx
    mov cx, 0FFFFh  
    lopa:
        mov bx, 50
        lopb:
            dec bx
            cmp bx, 0
            jnz lopb
    loop lopa
    pop bx
    pop cx
    call check_if_eaten
    ret
endp delay
  1. 蛇身存储地址非法
    playgame过程中你用xor bx,bx将bx置0,往[bx]等地址写入蛇身坐标,此时ds指向数据段,地址0属于系统中断向量表,你直接改写了系统内存,蛇身坐标没有正确存储,还会触发系统异常。
    修复方案:在数据段定义专门的蛇身存储数组:
; DATASEG 中新增
snake_body dw 100 dup(0)

playgame中写入坐标时替换xor bx,bx为mov bx, offset snake_body。
3. 蛇身更新长度读取错误
update_snake过程中mov cx, offset snake_length是把snake_length变量的地址赋值给cx,而不是读取蛇的长度值,导致循环更新逻辑异常。
修复方案:改为mov cx, [snake_length]。
4. 键盘检测逻辑写反
movement过程中int 16h ah=1的作用是检测是否有按键按下,有按键时ZF=0,你写的jnz skip会导致有按键时跳过读键逻辑,无按键时才读键,逻辑完全相反。
修复方案:改为jz skip。
5. 道具生成逻辑错误+无渲染步骤
random过程中mov ah, [byte cs:bx]的bx没有初始化,读取的内存地址完全随机,且只生成了低8位列坐标,没有行坐标,也没有将道具渲染到显存,所以道具不显示。同时Clock的定义是es:6Ch,调用时需要保证es指向0段才能正确读取系统时钟。

调试定位方法

DOSBOX环境下可以用debug工具加载编译后的程序,用t命令单步执行,逐行查看寄存器、栈、对应内存地址的内容是否符合预期,即可快速定位错误位置。

内容的提问来源于stack exchange,提问作者user17341742

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 04:45:05