通过用后面 5 个单词的总和替换其中的一些单词来更改 3D 数组

问题描述 投票:0回答:1

给定的逻辑段

 I1 db ?
 I2 db ?
 I3 db ?
 A1 dw 5 dup (6 dup (0fh,4 dup (0)))
 Data1 ends
  1. 创建一段代码(例如名称为Code1),在其中实现以下任务:替换代码中的所有单词 三维数组 A1 的值为 0fh,其中 使用索引跟随(通过段中的偏移量)5 个单词 I1,I2,I3(位于地址 I1,I2,I3 的值)。
  2. 再创建一个逻辑数据段(例如命名为Data2),其中设置指令A2 dw 5 dup(6 dup(0fh,4 dup(0)))
  3. 创建另一个逻辑代码段(例如,名称为Code2),其中使用链命令执行步骤1的任务 搜索值 0fh。计算后,比较中的值 数组 A1 和 A2。确保控制权无条件移交 使用间接段间控制将段 Code1 转换为段 Code2 转移。
  ;for MASM 5.00 translator
  ;for DOS
  
  .386
  .MODEL flat ; for MASM 5.00

我无法理解此任务中汇编代码的逻辑。

我的代码:

    .386
Data1 segment
I1 db ?
I2 db ?
I3 db ?
A1 dw 5 dup (6 dup (0fh,4 dup (0)))
Data1 ends

Data2 segment
A2 dw 5 dup (6 dup (0fh,4 dup (0)))
Data2 ends

Code1   segment use16 
    assume  cs:Code1, ds:Data1
start: 

    mov [I1], 0
    mov [I2], 0
    mov [I3], 0
    mov ax, DATA1
    mov ds, ax

    L1:
        L2:
            L3:
                movzx ax, byte ptr [I1]
                imul bx, ax, 6*5*2      
                movzx ax, byte ptr [I2]
                imul ecx, ax, 5*2               
                xor esi,esi
                movzx ax, byte ptr [I3]
                mov si, ax          
                lea di, [ecx + esi*2]   
                cmp A1[bx+di],0fh
                jne NEXT
                mov ax,0
                add ax,[A1+bx+di+2]
                add ax,[A1+bx+di+4]
                add ax,[A1+bx+di+6]
                add ax,[A1+bx+di+8]
                add ax,[A1+bx+di+10]
                mov [A1+bx+di],ax
    NEXT:
        inc I3
        cmp I3, 5
        jle L3
        mov I3, 0
        inc I2
        cmp I2, 6
        jle L2
        mov I2, 0
        inc I1
        cmp I1, 5
        jle L1
    
    jmp far ptr start2 
Code1   ends


Code2   segment use16
        assume cs:Code2, ds:Data1, es:Data2

start2:
    mov      ax,data1      
    mov      ds,ax     
    mov      ax,data2        
    mov      es,ax     
    mov cx, 150d
    mov di, OFFSET A2
    mov ax, 0fh
    cld
L:
    repnz scasw
    sub di, 2
    xor dx,dx
    add dx,[A2+di+2]
    add dx,[A2+di+4]
    add dx,[A2+di+6]
    add dx,[A2+di+8]
    add dx,[A2+di+10]
    mov [A2+di],dx
    add di, 2
    dec cx
    cmp cx,0
    jg L
    mov si,OFFSET A1
    mov di,OFFSET A2
    cld
    repz cmpsw
    sub si, 2
    sub di, 2
    mov bx,A1[si]
    mov dx,A2[di]


    mov ax, bx
    sub ax, dx 
    mov ax,4c00h 
    int 21h
Code2 ENDS
 end start2
arrays assembly nested-loops x86-16 masm
1个回答
0
投票

数据

使用索引 I1、I2、I3 将三维数组 A1 中的所有字替换为值 0fh 的以下(通过段中的偏移量)5 个字的总和

至少对我来说,这听起来好像你不应该关心读取数组之外的内存。你也是这样解决的。我提到这一点是因为它会影响比较两个数组(A1A2)的结果;如果数组之后内存中的垃圾有任何不同,那么

repe cmpsw
可能会产生错误的结果。

Data1 segment
I1 db ?
I2 db ?
I3 db ?
A1 dw 5 dup (6 dup (0fh,4 dup (0)))
Data1 ends

Data2 segment
A2 dw 5 dup (6 dup (0fh,4 dup (0)))
Data2 ends

我假设这些数据段是 16 字节对齐的,并且不保证末尾的填充。我建议如下:

Data1 segment
I1 db 0
I2 db 0
I3 db 0
   db 0                              <<< Word-alignment for A1 array
A1 dw 5 dup (6 dup (15, 4 dup (0)))
   db 0                              <<< Filler for consistent results
Data1 ends

Data2 segment
A2 dw 5 dup (6 dup (15, 4 dup (0)))
   db 0                              <<< Filler for consistent results
Data2 ends

第一种方法

您的三重嵌套循环迭代次数过多!当行中有 5 个元素时,I3 变量中从零开始的索引范围可以从 0 到 4。使用像

cmp I3, 5
jle L3
这样的一对指令,您将允许使用无效索引 5。其他索引也存在同样的错误。

mov [I1], 0
mov [I2], 0
mov [I3], 0
mov ax, DATA1
mov ds, ax

你认为如果在使用这些依赖于 DS 的mov指令之前

不设置 DS 段寄存器,CPU 会将这些零字节存储在哪里?

下面是我对这些嵌套循环的重写。我避免在最内部的循环中一遍又一遍地重复相同的计算,并且我选择仅使用 8086 代码。我知道您可以在实地址模式下使用 x86 指令,但我不喜欢的是您毫无理由地使用 16 位和 32 位寄存器的丑陋组合:

L1: mov al, 6*5*2 mul I1 mov di, ax ; DI is offset to a plane (a plane of rows and columns) L2: mov al, 5*2 mul I2 mov si, ax ; SI is offset to a row within a plane L3: xor bx, bx mov bl, I3 shl bx, 1 ; BX is offset to an element within a row add bx, si ; Address of current element is A1+di+si+bx cmp [A1+bx+di], 15 jne NEXT mov ax, [A1+bx+di+2] add ax, [A1+bx+di+4] add ax, [A1+bx+di+6] add ax, [A1+bx+di+8] add ax, [A1+bx+di+10] mov [A1+bx+di], ax NEXT: inc I3 cmp I3, 5 jb L3 mov I3, 0 inc I2 cmp I2, 6 jb L2 mov I2, 0 inc I1 cmp I1, 5 jb L1
第二种方法

当该

repne scasw

指令因找到值15而停止时,DI寄存器指向查找结果
后面,并且CX寄存器包含剩余项目的数量。在循环底部使用 dec cx
 是错误的!

add dx,[A2+di+2] add dx,[A2+di+4] add dx,[A2+di+6] add dx,[A2+di+8] add dx,[A2+di+10] mov [A2+di],dx

这些指令将

A2数组的地址添加两次!一次通过 mov di, offset A2

 初始化 DI,第二次通过在寻址模式中提及 
[A2+ ...

以下是我的重写并应用了更正。请注意,不必先将 DI 减 2,然后再将 DI 加 2。稍微调整一下偏移量会更好。偏移量也可以是负数,如

mov es:[di-2], ax

:

mov ax, data1 mov ds, ax mov ax, data2 mov es, ax mov cx, 5*6*5 mov di, offset A2 cld L: mov ax, 15 repne scasw mov ax, es:[di] add ax, es:[di+2] add ax, es:[di+4] add ax, es:[di+6] add ax, es:[di+8] mov es:[di-2], ax test cx, cx jnz L
支票

sub si, 2 sub di, 2 mov bx,A1[si] mov dx,A2[di] mov ax, bx sub ax, dx mov ax,4c00h int 21h

这里,这些

mov

指令将数组的地址相加
两次!一次通过 SI / DI 的初始化,第二次通过在寻址模式中提及 A1 / A2。 当然,您应该使用偏移量 -2,这比从索引寄存器中减去 2 更好。
如果用函数号覆盖 AX 来退出程序,计算
AX = BX - DX
的结果就会丢失!

我的建议是返回 DOS.Exitcode AL 中的差异:

mov si, offset A1 mov di, offset A2 repe cmpsw mov al, [si-2] sub al, es:[di-2] mov ah, 4Ch int 21h
    
© www.soinside.com 2019 - 2024. All rights reserved.