汇编语言中的寻址问题(含有变量名的相对寻址)

输入一个正整数数组,数组长度小于10,数组元素都小于10,然后将所有偶数的和(没有偶数则视为0)减去所有奇数的和(没有奇数则视为0),结果保存在dl中。

输入描述

首先输入一个数n(1<=n<10),表示正整数数组的长度。接下来n空,分别输入n个正整数Ni(0<Ni<10,0<=i<n),数之间不含空格,回车或者换行。

输出描述

只需将结果保存在dl中。

(看103行)

;;//PREPEND BEGIN
.model small
.stack
.data
    ARRAY db 10 DUP(0)   ; 数组,长度为10
    LEN db ?          ; 数组长度
    INDEX db ?           ; 循环索引
    CURRENT_NUM db ?     ; 当前元素
    EVEN_SUM db 0        ; 偶数和
    ODD_SUM db 0         ; 奇数和

.code

print_num proc near
    push dx     ; 保存寄存器
    mov dh,dl   ; 保存dl
    and dh,80h  ; 判断是否为负数
    jnz negL    ; 若为负数,跳转到negL
    jmp nxt    ; 若为正数,跳转到nxt
negL:   ; 若为负数,先输出负号
    mov dh,dl   ; 保存dl
    mov dl, '-' ; 输出负号
    mov ah, 02h ; 功能号2,输出字符
    int 21h    ; 调用中断
    neg dh    ; 取反dh
    mov dl,dh   ; 将dh赋给dl
nxt:
    xor  ah, ah     ; 除法时,ah必须为0
    mov  al, dl    ; 将dl赋给al
    mov  dh, 10   ; 除数为10
    div  dh     ; 除以10
    ;除以10后商是否为0
    test al, 0ffh   ;若为0,则代表原数为一位数
    jz   single ;商不为0,至少为两位数
    push ax     ;保存ax
    xor  ah, ah     ;除法时,ah必须为0
    div  dh     ;除以10
    test al, 0ffh   ;同理,若商为0,代表为两位数
    jz   two    ;商为0时,余数不可能也为0,这样是个位数
    push ax     ;保存ax
    mov  dl, al     ;余数为个位数
    add  dl, '0'    ;转换为字符
    mov  ah, 02h    ;功能号2,输出字符
    int  21h    ;调用中断
    pop  ax     ;恢复ax
two:
    mov  dl, ah     ;余数为十位数
    add  dl, '0'    ;转换为字符
    mov  ah, 02h    ;功能号2,输出字符
    int  21h    ;调用中断
    pop  ax     ;恢复ax
single:
    mov  dl, ah     ;余数为个位数
    add  dl, '0'    ;转换为字符
    mov  ah, 02h    ;功能号2,输出字符
    int  21h    ;调用中断
    pop  dx    ;恢复寄存器
    ret
print_num endp

start:
    mov ax,@data     ; 初始化数据段寄存器
    mov ds,ax     ; 初始化数据段寄存器
    ; 输入数组长度
    mov ah, 01H          ; 设置DOS功能调用的子功能号为01H(读取字符)
    int 21H              ; 执行DOS功能调用
    sub al, '0'          ; 将输入字符转换为数字
    mov LEN, al         ; 将数组长度保存到LEN中

    ; 输入数组元素
    mov INDEX, 0         ; 初始化循环索引为0

INPUT_LOOP:
    mov ah, 01H          ; 设置DOS功能调用的子功能号为01H(读取字符)
    int 21H              ; 执行DOS功能调用
    sub al, '0'          ; 将输入字符转换为数字
    mov CURRENT_NUM, al ; 将当前元素保存到CURRENT_NUM中
    mov al, INDEX       ; 将循环索引保存到AL中
    mov bx,offset ARRAY ; 将数组的偏移地址保存到BX中
    mov cl,CURRENT_NUM      ; 将当前元素保存到CL中
    xor si,si        ; 将SI寄存器清零,用于保存数组索引
    xor ch,ch     ; 将CH寄存器清零
    xor ah,ah   ; 将AH寄存器清零
    add si,bx    ; 将数组的偏移地址保存到SI中
    add si,ax   ; 将循环索引加到SI中
    mov [si], cl ; 将当前元素保存到数组中
    inc INDEX            ; 循环索引加1
    mov al,INDEX    ; 将循环索引保存到AL中
    mov ah,LEN    ; 将数组长度保存到AH中
    cmp al, ah      ; 判断循环索引是否达到数组长度
    jb INPUT_LOOP        ; 如果循环索引小于数组长度,继续输入下一个元素

    ; 计算偶数和和奇数和
    xor DL, DL           ; 将DL寄存器清零,用于保存结果

    mov INDEX, 0         ; 初始化循环索引为0
;;//PREPEND END

    ;;//TEMPLATE BEGIN
    ;;//
    xor ch,ch
cir:mov si,offset array
    mov al,[si+len-1]          ;注意这里!!!!
    mov ah,al
    mov cl,7
    shl ah,cl
    cmp ah,0
    jz jud
    add ch,al
    jmp asd
jud:add dl,al
asd:dec len
    jnz cir
    sub dl,ch

    ;;//TEMPLATE END

;;//APPEND BEGIN
    call print_num  ; 显示结果
    mov ah,4CH  ; 设置DOS功能调用的子功能号为4CH(程序退出)
    int 21H

end start
;;//APPEND END

这个程序中,【si+len-1】原本是想取array中下标为(len-1)的元素,但这样的表达式为寄存器变址寻址,即把len看做地址,取了len【si+1】的值,所以产生了错误,直接写为【array+len-1】也不对,因为会把两个都识别为标号(地址)。所以可以先 add si,len,再用 【si-1】,则变为寄存器间接寻址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值