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

汇编实现C语言strstr()模拟函数遇无输出问题求助

汇编实现strstr无输出问题排查

核心错误点

1. 栈参数访问完全错误

  • 在start流程中,你先压入string1的偏移,再压入string2的偏移,调用strstr时栈结构为:返回地址 → string2偏移 → string1偏移。原代码错误地将[bp+4](返回地址)当作string1的指针,导致后续所有地址访问失效。
  • 调用search前压入了di和si,但原代码用[bp+10]、[bp+12]访问参数,属于无意义的越界操作;且返回时错误执行pop bx、pop dx(未提前push过这些寄存器),直接破坏栈平衡,导致程序执行混乱。

2. 字符串结束判断错误

int 21h的0Ah号输入功能,不会自动在字符串末尾添加'$',有效字符范围由缓冲区第二个字节(实际输入长度)决定。原代码用cmp al, '$'判断结束,会导致遍历到无关内存,触发未知错误。

3. 函数返回栈操作混乱

strstr和search的返回逻辑中,错误地弹出未入栈的bx、dx寄存器,导致栈指针错乱,函数返回后程序无法正常执行。

4. 结果打印逻辑错误

原print_result的循环逻辑错误,test ax, ax后直接跳转到除法步骤,无法正确将地址偏移转换为十进制输出。

修正后的代码

assume cs:code, ds:data

data segment
    newline db 0Dh, 0Ah, '$'
    string1 db 100, 99 dup (0)  ; 0Ah输入缓冲区:[0]最大长度, [1]实际长度, [2...]字符
    string2 db 100, 99 dup (0)
    not_found_message db 'Not found', '$'
data ends

code segment
; strstr参数:(主串指针, 子串指针)
; 返回ax=子串在主串有效字符中的偏移,未找到则返回-1
strstr proc
    push bp
    mov bp, sp

    ; 栈结构:bp+4=返回地址, bp+6=子串指针, bp+8=主串指针
    mov di, [bp+8]       ; 主串缓冲区起始
    mov cl, [di+1]       ; 主串实际字符数
    add di, 2            ; 主串有效字符起始位置
    mov di_end, di
    add di_end, cx       ; 主串结束位置(下一个字节)

    mov si, [bp+6]       ; 子串缓冲区起始
    mov cl, [si+1]       ; 子串实际字符数
    mov si_len, cx
    add si, 2            ; 子串有效字符起始位置
    cmp si_len, 0
    je success1          ; 子串为空,直接返回主串起始偏移

inner_loop:
    cmp di, di_end
    jge failed1          ; 遍历完主串未找到,返回失败

    ; 调用search匹配当前位置
    push di
    push si
    push si_len
    call search

    add sp, 6            ; 清理栈上3个参数(各2字节)
    cmp ax, 1
    je success1          ; 匹配成功,计算偏移返回

    inc di
    jmp inner_loop

success1:
    sub di, [bp+8]       ; 计算相对于主串缓冲区的偏移
    sub di, 2            ; 转换为相对于有效字符的偏移
    mov ax, di
    pop bp
    ret 4                ; 自动清理栈上的主串、子串参数(各2字节)
failed1:
    mov ax, -1
    pop bp
    ret 4
strstr endp

; search参数:(主串当前位置, 子串起始, 子串长度)
; 返回ax=1匹配成功,ax=0失败
search proc
    push bp
    mov bp, sp

    mov di, [bp+10]      ; 主串当前位置
    mov si, [bp+8]       ; 子串起始
    mov cx, [bp+6]       ; 子串长度
    jcxz success2        ; 子串长度为0,直接判定成功

custom_loop:
    mov al, [di]
    mov bl, [si]
    cmp al, bl
    jne failed2          ; 字符不匹配,返回失败

    inc di
    inc si
    loop custom_loop     ; 遍历完子串所有字符

success2:
    mov ax, 1
    pop bp
    ret
failed2:
    mov ax, 0
    pop bp
    ret
search endp

start:
    mov ax, data
    mov ds, ax

    ; 输入主串
    mov dx, offset string1
    mov ah, 0Ah
    int 21h
    ; 换行
    mov dx, offset newline
    mov ah, 09h
    int 21h
    ; 输入子串
    mov dx, offset string2
    mov ah, 0Ah
    int 21h
    ; 换行
    mov dx, offset newline
    mov ah, 09h
    int 21h

    ; 压入参数:先主串,再子串(栈后进先出)
    push offset string1
    push offset string2
    call strstr

    ; 处理返回值
    cmp ax, -1
    je not_found

    ; 打印找到的偏移量(十进制)
    mov bx, ax
    cmp bx, 0
    je print_zero
print_loop:
    xor dx, dx
    mov ax, bx
    mov cx, 10
    div cx               ; ax=商,dx=余数
    push dx              ; 余数入栈(逆序存储)
    mov bx, ax
    test bx, bx
    jnz print_loop
print_digits:
    pop dx
    add dl, '0'
    mov ah, 02h
    int 21h
    jmp print_done
print_zero:
    mov dl, '0'
    mov ah, 02h
    int 21h
print_done:
    mov dx, offset newline
    mov ah, 09h
    int 21h

    mov ah, 4ch
    int 21h

not_found:
    mov ah, 09h
    mov dx, offset not_found_message
    int 21h
    mov dx, offset newline
    mov ah, 09h
    int 21h
    mov ah, 4ch
    int 21h

; 全局变量存储主串结束位置和子串长度
di_end dw ?
si_len dw ?
code ends
end start

修正说明

  1. 栈参数规范:明确每个函数的栈结构,使用ret n自动清理栈参数,避免手动操作栈导致的错误。
  2. 字符串遍历逻辑:根据0Ah输入缓冲区的实际长度确定有效字符范围,不再依赖'$'判断结束。
  3. 函数返回逻辑:简化返回流程,确保栈平衡,避免非法寄存器弹出操作。
  4. 结果打印:修复十进制转换逻辑,正确将偏移量转换为字符输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:15:55