由两个字符串的 summing/subtracting 个字符创建一个新数组

Creating a new array by summing/subtracting characters of two strings

从 2 个字节数组 S1 和 S2 开始,应该根据以下规则创建第三个数组:在偶数位置应该是 S1 和 S2 中特定字符的总和,在奇数位置位置应该是 S1 和 S2 中特定字符的差异

示例:

;S1: 1, 2, 3, 4

;S2: 5, 6, 7, 8

;D: 6, -4, 10, -4

我试过根据 2 "for loops" 按以下方式实现它,但在尝试了几次之后,我发现它可能永远不会工作,因为它们不是同时的。我考虑过只使用一个并基于比较来创建总和或差异。问题是,我不太确定这种比较应该如何进行(cmp si,?)。对此有任何建议将不胜感激。

ASSUME cs:text_,ds:data_

data_ SEGMENT

s1 db '1','2','3','4'
l equ $-s1 
s2 db '5','6','7','8'
d db l dup (?)

data_ ENDS

text_ SEGMENT
start:
mov ax, data_
mov ds, ax
mov es, ax
mov si, offset s1
mov bx, offset s2
mov di, offset d  
cld
mov cx, l 
jcxz endi

xor cx,cx   ; cx-register is the counter, set to 0
loop1:
    lodsb    ;current character of s1 is stored in al
    add al, byte ptr es:[bx] ;the character of s2, which is on the same position as the one stored in al, is added to al
    stosb   ;data from al is moved to di
    add cx, 2   ;cx is incremented
    cmp cx,l    ; Compare cx to the limit
jl loop1   ; Loop while less 

mov al, 0   ; al is emptied
mov cx, 1   ; cx-register is the counter, set to 1
loop2:
    lodsb   ;current character of s1 is stored in al
    sub al, byte ptr es:[bx] ;the character of s2, which is on the same position as the one stored in al, is added to al
    stosb  ;data from al is moved to di
    add cx, 2 ;Increment
    cmp cx,l    ; Compare cx to the limit
jle loop2   ; Loop while less or equal

endi:
   mov ax, 4c00h
   int 21h
text_ ENDS
end start   

提前致谢,对任何mistakes/inconveniences感到抱歉。

正如@Jester 所指出的,双循环可以工作,这只是我将如何做的一个例子。然而这个例子是破坏性的,因为 s1 的内容被修改了。如果您想使用此模型,但要进行修改以完全符合您的示例,那么修改应该很容易概念化。

    ASSUME cs:text_,ds:data_

        data_ SEGMENT
    s1 db '1','2','3','4'
    s2 db '5','6','7','8'
        data_ ENDS

        text_ SEGMENT
    start:
            mov     ax, data_
            mov     ds, ax
            mov     es, ax

            mov     si, offset s1
            mov     di, offset s2
            mov     cx, di
            sub     cx, si              ; Now you have the number of entries in CX
            xor     bx, bx
            jcxz    endi

        Next:   
            lodsb
            mov     ah, [di]
            bt      bx, 0               ; Is bit on, then we want to subtract
            jnc     @F - 2
            sub     al, ah
            jmp     @F
            add     al, ah

     @@:    stosb
            xor     bl, 1               ; Toggle add or subtract indicator
            loop    Next

        endi:
            mov     ax, 4c00h
            int     21h

        text_ ENDS
    end start   

注意:我使用 NASM,所以希望这个例子适用于 MASM

代码存在一些问题。

  1. 您不能添加或减去 个字符。字符不存储为数字,而是存储为 ASCII 码。您可以将 ASCII 码想象成向显示器显示特定字符​​的命令。处理器需要另一种格式来将其作为整数处理。你必须转换它(如果你想显示它,然后再转换回来)。字符的 ASCII 部分位于高半字节。要获得整数,请将其删除(AND 0FhSUB 48)。要获取字符,请将 ASCII 部分添加到整数(OR 30hADD 48)。梯子是你作业的主要部分,因为处理负号和多于一位的数字有点挑战。

  2. SI、DI 和 BX 必须在您的 2 循环解决方案中增加 2。 LODSBSTOSB 仅递增 1。因此您为该寄存器添加了额外的递增。你忘了增加 BX。

  3. 这里没关系,但是... JLJLE 执行 signed 比较。 CX 不太可能变成负数。所以将其更改为未签名的 camparisons JBJBE.

以下代码将结果作为整数存储在 d 中:

ASSUME cs:text_,ds:data_

data_ SEGMENT

s1 db '1','2','3','4'
l equ $-s1
s2 db '5','6','7','8'
d db l dup (?)

data_ ENDS

text_ SEGMENT
start:
mov ax, data_
mov ds, ax
mov es, ax
mov si, offset s1
mov bx, offset s2
mov di, offset d
cld
mov cx, l
jcxz endi

xor cx,cx                       ; cx-register is the counter, set to 0
loop1:
    lodsb                       ; current character of s1 is stored in al
    mov ah, byte ptr es:[bx]    ; the character of s2, which is on the same position as the one stored in al, is added to al
    and ax, 0F0Fh               ; Remove the ASCII parts in AH and AL
    add al, ah
    stosb                       ; data from al is moved to di
    add bx, 2                   ; Increment
    add si, 1                   ; Increment
    add di, 1                   ; Increment
    add cx, 2                   ; cx is incremented
    cmp cx,l                    ; Compare cx to the limit
;jl loop1                       ; Loop while less
jb loop1                        ; Loop while below

mov si, offset s1 + 1           ; Reinitialize SI, DI and BX at odd indices
mov bx, offset s2 + 1
mov di, offset d + 1
mov cx, 1                       ; cx-register is the counter, set to 1
loop2:
    lodsb                       ; current character of s1 is stored in al
    mov ah, byte ptr es:[bx]    ; the character of s2, which is on the same position as the one stored in al, is added to al
    and ax, 0F0Fh               ; Remove the ASCII parts in AH and AL
    sub al, ah
    stosb                       ; data from al is moved to di
    add bx, 2                   ; Increment
    add si, 1                   ; Increment
    add di, 1                   ; Increment
    add cx, 2                   ; Increment
    cmp cx,l                    ; Compare cx to the limit
;jle loop2                      ; Loop while less or equal
jbe loop2                       ; Loop while below or equal

endi:
   mov ax, 4c00h
   int 21h
text_ ENDS
end start

单循环解决方案中的比较非常简单。想想二进制!奇数的最右边位是 1,偶数是 0。您可以 AND 带 1 的数字并得到 0(未设置)或 1(已设置)。 TEST 是一种特殊的 x86 指令,它执行 AND 但仅设置标志而不更改寄存器。如果结果不为空 -> 奇数,则不设置零标志(参见 JNZ)。

ASSUME cs:text_,ds:data_

data_ SEGMENT

s1 db '1','2','3','4'
l equ $-s1
s2 db '5','6','7','8'
d db l dup (?)

data_ ENDS

text_ SEGMENT
start:
mov ax, data_
mov ds, ax
mov es, ax
mov si, offset s1
mov bx, offset s2
mov di, offset d
cld
mov cx, l
jcxz endi

xor cx,cx                       ; cx-register is the counter, set to 0
loop1:
    lodsb                       ; current character of s1 is stored in al
    mov ah, byte ptr es:[bx]    ; the character of s2, which is on the same position as the one stored in al, is added to al
    and ax, 0F0Fh               ; Remove the ASCII parts in AH and AL
    test cx, 1                  ; Odd?
    jnz odd                     ; Yes -> jump to the subtraction
    even:
    add al, ah
    jmp l2                      ; Skip the subtraction
    odd:
    sub al, ah
    l2:
    stosb                       ; data from al is moved to di
    add bx, 1                   ; Increment
    add cx, 1                   ; cx is incremented
    cmp cx,l                    ; Compare cx to the limit
jbe loop1                       ; Loop while below

endi:
   mov ax, 4c00h
   int 21h
text_ ENDS
end start

I've considered going just with one and based on a comparison, to create the sum or the difference.

这就是你如何只用一个循环(你根据索引值求和或求差):

只需用以下代码替换您的两个循环:-

  mov cl, 2              ; store 2 in cl which is used to check later if the index is even or odd
  loop1:
        lodsb            ; current character of s1 is stored in al
        mov dl, al       ; save al in dl   
        mov ax, si       ; store the value of si in ax
        dec ax           ; since lodsb increments si we have to decrement it to get the current index  
        div cl           ; divide al with cl
        mov al, dl       ; get the stored value from dl to al 
        cmp ah, 0        ; check if remainder is zero (div instruction stores remainder in ah and quotient in al if divisor is 8bit)
        jne oddNum       ; if no then we are at odd position otherwise we are at even position 
        add al, byte ptr es:[bx] 
        jmp continue
        oddNum:
        sub al, byte ptr es:[bx]      ;the character of s2, which is on the same position as the one stored in al, is added to al
        continue:
        stosb                ; data from al is moved to di    
        inc bx               ; increment bx so that it points to next element in s2 
        cmp si,l             ; Compare cx to the limit
    jl loop1                 ; Loop while less 

在上面的代码中,您将根据 si 寄存器的值(可以是偶数或奇数)求和或求差