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

Intel 64汇编集合差集循环打印异常:仅输出首个元素

Intel 64汇编集合差集打印问题:仅输出第一个元素后退出循环

我用Intel 64汇编实现集合差集打印功能时遇到问题,预期循环打印出差集的所有元素,但实际仅输出第一个元素后就退出循环。相关代码如下:

msjFinal                db "}",10,0
msjElemento             db "%c ,",0
msjDiferencia           db "Diferencia entre conjuntos: { ",0

conjuntos_0             dw  ''
conjuntos_1             dw  '2', '8', '6', '7', '5', '3', '8', 'A', 'B', 'D', 'G', 'H', 'U', 'Y', 'Q', 'R', 'Q', '0', 'W', 'L'      
conjuntos_2             dw  '1', '2', '3', '4', '5', '6', '7', '8', '1', '9', 'P', 'P', 'Q', 'R', 'Z', 'W', 'A', 'B', 'C', 'D'      
conjuntos_3             dw  '6', '7', '1', '9', '8', '9', 'L', 'A', 'D', 'F', 'P', 'R', 'X', 'S', '0', 'M', 'N', 'Q', 'Z', '5'      
conjuntos_4             dw  '1', '2', '5', '6', '7', '8', 'A', 'B', 'P', 'O', 'L', 'I', 'S', 'O', '0', 'E', '3', 'N', 'M', 'Z'      
conjuntos_5             dw  '3', '4', '7', '8', '1', '9', 'N', 'E', 'R', 'O', 'K', 'M', 'V', 'F', 'I', 'A', 'C', 'P', 'D', 'W'      
conjuntos_6             dw  '5', '3', 'J', '2', 'T', '1', '7', '8', 'X', 'S', 'U', 'Z', 'E', 'B', 'A', 'L', 'P', 'V', 'W', 'Q'      

conjuntos               dq conjuntos_0, conjuntos_1, conjuntos_2, conjuntos_3, conjuntos_4, conjuntos_5, conjuntos_6

diferenciaDeConjuntos:

    mov             rdi,msjDiferencia
    sub             rsp,8
    call            printf
    add             rsp,8

    mov             rcx,[nConjunto1]
    mov             rdi,[conjuntos + rcx * 8]       ; cargo a rdi el 1er conjunto

    mov             rcx,[nConjunto2]           
    mov             rsi,[conjuntos + rcx * 8]       ; cargo a rsi el 2do conjunto

    mov             r11,0                           ; indice para pasar de elemento conjunto1
    mov             r8,0                            ; indice para pasar de elemento conjunto2

diferenciaLoop:
    mov             dx, word[rsi + r8 ]             ; elemento del segundo conjunto

    sub             rsp,8
    call            compararElementosPertenencia    ; salta a funcion de pertenencia
    add             rsp,8
    
    cmp             byte[elementoPertenece],0       ; si es 1 no lo necesito paso de elemento, si no lo agrego
    je              agregarElementoDiferencia
    
    add             r8,2                            ; siguiente elemento

    cmp             r8,40
    je              terminarPrint

    jmp             diferenciaLoop

agregarElementoDiferencia:
    
    mov             word[resultadoElemento],dx    ; agrego el elemento

    mov             rdi,msjElemento
    mov             rsi, [resultadoElemento]
    sub             rsp,8
    call            printf
    add             rsp,8

    add             r8,2

    cmp             r8,40
    jb              diferenciaLoop

    sub             rsp,8
    call            terminarPrint
    add             rsp,8

terminarPrint:

    mov             rdi,msjFinal 
    sub             rsp,8
    call            puts
    add             rsp,8

    sub             rsp,8
    call            quiereSeguirOSalir
    add             rsp,8
    
    ret

问题分析

  1. 差集逻辑完全颠倒
    集合差集A-B的定义是「属于集合A但不属于集合B的元素」,但当前代码是遍历集合B的元素,判断是否不在集合A中,实际计算的是B-A,和预期功能不符。

  2. 循环退出逻辑错误
    在agregarElementoDiferencia中,当遍历到集合B的最后一个元素时,执行call terminarPrint,而terminarPrint末尾的ret会直接返回至diferenciaDeConjuntos的调用者,导致程序直接退出,无法继续循环。

  3. 寄存器未妥善保存
    调用printf等C标准库函数时,System V AMD64调用约定会破坏r8等易失性寄存器的值,而r8是你的循环计数器,这会导致循环索引异常,提前终止循环。

修复方案

1. 修正差集逻辑

改为遍历集合A的元素,逐个判断是否存在于集合B中,不存在则打印该元素。

2. 修复循环退出逻辑

将call terminarPrint改为跳转(jmp terminarPrint),避免ret导致提前返回。

3. 保存易失性寄存器

调用C函数前,将循环计数器等需要保留的寄存器压入栈中,调用后恢复。

修改后的代码示例

diferenciaDeConjuntos:

    mov             rdi,msjDiferencia
    sub             rsp,8
    call            printf
    add             rsp,8

    mov             rcx,[nConjunto1]
    mov             rdi,[conjuntos + rcx * 8]       ; 集合A:差集A-B的左集合
    mov             rcx,[nConjunto2]           
    mov             rsi,[conjuntos + rcx * 8]       ; 集合B:差集A-B的右集合

    mov             r11,0                           ; 集合A的遍历索引
    mov             r8,0                            ; 集合B的遍历索引(用于元素存在性判断)

diferenciaLoop:
    cmp             r11,40                          ; 检查是否遍历完集合A的所有元素
    je              terminarPrint

    mov             dx, word[rdi + r11 ]            ; 取集合A的当前元素
    mov             r8,0                            ; 重置集合B的索引,准备查找

buscarEnB:
    cmp             r8,40
    je              agregarElementoDiferencia       ; 遍历完B未找到,说明元素属于A-B,需要打印

    mov             cx, word[rsi + r8 ]
    cmp             dx,cx
    je              siguienteElementoA              ; 在B中找到元素,跳过当前A元素

    add             r8,2
    jmp             buscarEnB

siguienteElementoA:
    add             r11,2
    jmp             diferenciaLoop

agregarElementoDiferencia:
    mov             word[resultadoElemento],dx

    push            r11                            ; 保存集合A的索引,避免printf破坏
    mov             rdi,msjElemento
    mov             rsi, [resultadoElemento]
    sub             rsp,8
    call            printf
    add             rsp,8
    pop             r11                            ; 恢复索引寄存器

    add             r11,2
    jmp             diferenciaLoop

terminarPrint:
    mov             rdi,msjFinal 
    sub             rsp,8
    call            puts
    add             rsp,8

    sub             rsp,8
    call            quiereSeguirOSalir
    add             rsp,8
    
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:29:52