assembly 根据偶数/奇数弹出计数右移/左移

emeijp43  于 2022-12-13  发布在  其他
关注(0)|答案(2)|浏览(116)

我的代码应该检查一个变量是奇数位还是偶数位,如果是偶数位,则将打开的位数右移,如果是奇数位,则将打开的位数左移。
这是我的代码:

IDEAL
MODEL small
STACK 100h
DATASEG
TAV db 00001001b
t_copy db 00001001b

CODESEG
start:

    xor cx,cx
    mov cx,8
    xor al,al
    L1:
        shr [t_copy],1
        jnc nc
        inc al
        nc:
        
        dec cx
        jnz L1
    mov cl,al
    and al,00000001h
    
    cmp al,0h
    jz even_               
    jnz odd
    
    
    odd:
        shl [TAV],cl
        jmp exit
    even_:
        shr [TAV],cl
    
exit:
    mov ax, 4c00h
    int 21h
END start

当我运行代码的时候,它没有移动,也没有改变变量的值。我认为它改变了变量的值,作为内存中的索引。你知道我怎么修复它吗?

w51jfk4q

w51jfk4q1#

当您运行TASM为您创建的.EXE时,执行从代码段中的 start 标签开始,并且CS段寄存器指向它。为了您的程序正常运行,类似地,DS段寄存器应该指向您程序的数据段。遗憾的是,默认情况下并非如此,因为DS指向程序段前缀PSP。您必须使用以下代码自己设置DS:

mov  ax, @data
mov  ds, ax

如果您选择MODEL tiny(而不是MODEL small),则不会出现问题,因为所有4个段寄存器彼此相等。

xor cx,cx
mov cx,8

在加载寄存器之前将寄存器清零是不必要的操作。

jnc nc
inc al
nc:

虽然这种构造是正确的,但是如果进位被设置,则通过adc al, 0增加AL可以简单得多。如果进位标志被清除,则不添加任何内容,如果进位标志被设置,则添加1。

and al,00000001h
cmp al,0h

检查一个值是偶数还是奇数是通过检查最低有效位来完成的,你做得很好。关键是,你不需要cmp,因为and指令已经定义了你想用于分支的零标志。
更好的是,如果你使用test而不是and,你会收到相同的零标志,并且根本不修改寄存器。写test cl, 1可以保存你使用额外的寄存器。

jz even_
jnz odd

odd:

这个jnz条件跳转没有任何作用。如果条件满足,执行跳转到odd 标签,如果条件不满足,执行 * 福尔斯通过**进入 odd 标签。

shr [t_copy],1

你可以通过处理寄存器中的数据而不是内存中的数据来改进你的解决方案。你也不需要副本。

CODESEG
start:
    mov  ax, @data
    mov  ds, ax

    xor  cx, cx     ; CL is popcount, CH is a convenient 0
    mov  al, [TAV]
L1:
    shr  al, 1      ; The bit that comes out of AL
    adc  cl, ch     ;   is added to CL
    test al, al     ; If AL got empty, further adding would be useless
    jnz  L1
    test cl, 1      ; Non-destructive checking of the least significant bit
    jnz  ON
    shr  [TAV], cl  ; Shift right if popcount is EVEN
    jmp  exit               
ON:
    shl  [TAV], cl  ; Shift left if popcount is ODD
exit:
sd2nnvve

sd2nnvve2#

编辑:下面描述的错误实际上并不存在,我误读了代码。
很接近了,但是这里有一个小错误。当执行and al,1时,实际上已经修改了al,并且原始的人口计数现在丢失了。幸运的是,有一个简单的方法可以解决这个问题,使用test al,1代替。这会像and al,1一样影响零标志。除了al保持与test之前的相同。因此,请尝试以下方法,看看是否有帮助:

mov cl,al
    test al,1
    
    ;cmp al,0h ;this line is redundant.
    jz even_               
    ;jnz odd   ;this line is redundant.
    odd:
        shl [TAV],cl
        jmp exit
    even_:
        shr [TAV],cl

相关问题