寻址方式的灵活运用(问题7.6,7.7,7.9)

7.6问题

问题:[bx+idata]的灵活运用

编程,将datasg段中每个单词的头一个字母改成大写

assume cs:codesg,ds:datasg
datasg segment
 db '1\. file       '
 db '2\. edit       '
 db '3\. search     '
 db '4, view       '
 db '5\. option     '
 db '6\. help       '
datasg ends
​
code segment
 start:......
codesg ends
end start 

分析:

其中定义的字符串在内存中的存放是这样的:

寻址方式的灵活运用(问题7.6,7.7,7.9)_第1张图片
1.png

定义了6个字符串,每个长度都是16个字节,需要进行6次循环,用一个变量R定位行,用常量定位列。过程如下:

  • BX先存放第一行的地址

  • mov cx,6 因为总共有六行

  • s:改变第BX行,第3列的字母为大写改变BX的值使它指向下一行的地址。

  • loop

也就是说,使用bx作变量,定位每行的起始地址,用3定位要修改的列,用[bx+idata]的方式来对目标单元进行寻址

代码:

assume cs:codesg,ds:datasg
datasg segment
 db '1\. file       '
 db '2\. edit       '
 db '3\. search     '
 db '4, view       '
 db '5\. option     '
 db '6\. help       '
datasg ends
​
code segment
 start: mov ax,datasg
 mov ds,ax
 mov bx,0

 mov cx,6
 s:mov al,[bx+3]  ;注意单位是字节,所以是al
 and al,11011111b
 mov [bx+3],al
 add bx,16
 loop s

 mov ax,4c00h
 int 21h
codesg ends
end start 

7.7问题

问题:[bx+SI]的灵活运用

编程,将datasg段中每个单词改写成大写字母

assume cs:codesg,ds:datasg
datasg segment
 db 'ibm       '
 db 'dec       '
 db 'dos     '
 db 'vax      '
datasg ends
​
code segment
 start:......
codesg ends
end start

分析:

其中定义的字符串在内存中的存放是这样的:

寻址方式的灵活运用(问题7.6,7.7,7.9)_第2张图片
2.png

在datasg中定义了4个字符串,每个长度为16个字节,因为他们是连续存放的,我们可以将这4个字符串看成一个4行16列的二维数组,按照要求,需要修改每一个单词,即二维数组的每一行的前三列。

进行4*3次的二重循环,使用R定位行,变量C定位列。外层循环按行来进行,内层循环按列来进行。过程如下:

  • R=第一行的地址

    mov cx,4

    S0:C=第一列的地址

    mov cx,3

    s:改变R行,C列的字母为大写

    C=下一列的地址

    loop s

    R=下一行的地址

    loop s0

使用bx来作变量,定位每行的起始地址,用si定位要修改的列,用[bx+si]的方式来对目标单元进行寻址

代码:

assume cs:codesg,ds:datasg
datasg segment
 db 'ibm       '
 db 'dec       '
 db 'dos       '
 db 'vax       '
datasg ends
​
code segment
 start:mov ax,datasg
 mov ds,ax
 mov bx,0

 mov cx,4
 s0:mov si,0
 mov cx,3
 s:mov al,[bx+si]
 and al,11011111b
 mov [bx+si],al

 inc si
 loop s

 add bx,16
 loop s0

 mov ax,4c00h
 int 21h

codesg ends
end start

这段代码,会陷入死循环,原因是cx的使用,程序是二重循环,但是只用了一个循环计数器,造成在进行内层循环的时候覆盖了外层循环的循环计数值。

在debug这个程序,可以发现是因为cx的错误导致的,但是多用一个计数器又不可能,因为loop指令默认使用cx为循环计数器。所以应该在每次开始内层循环的时候,将外层的cx值保存起来,在执行外层循环的loop指令前,再恢复外层循环的cx数值,可以使用dx来保存。

改进后的代码:

assume cs:codesg,ds:datasg
datasg segment
 db 'ibm       '
 db 'dec       '
 db 'dos       '
 db 'vax       '
datasg ends
​
code segment
 start:mov ax,datasg
 mov ds,ax
 mov bx,0

 mov cx,4
 s0:mov dx,cx          ;使用dx寄存器来临时保存cx的值
 mov si,0
 mov cx,3
 s:mov al,[bx+si]
 and al,11011111b
 mov [bx+si],al

 inc si
 loop s

 add bx,16
 mov cx,dx          ;在这里再恢复cx的值
 loop s0

 mov ax,4c00h
 int 21h

codesg ends
end start 

这个程序使用dx来临时保存cx的值,这是可以的,但是有可能dx这个值在内层循环中也会被使用,在这个程序中,si,cx,ax,bx,显然不能存放cx中的数据,因为这些寄存器在循环中也要使用,cs,ip,ds当然也不能使用,因为cs:ip时刻指向当前指令,ds指向datasg段。

所以现在讨论的是,程序中经常需要进行数据的暂存,可能是寄存器中的也可能是内存中的,我们应该怎么样做更为合理。

通用的方案是:使用内存,可以将需要暂存的数据放到内存单元中,需要使用的时候,再从内存单元中恢复,这样就需要开辟一段内存空间。

再改进后的代码:

assume cs:codesg,ds:datasg
datasg segment
 db 'ibm       '
 db 'dec       '
 db 'dos       '
 db 'vax       '
 dw 0          ;定义一个字,用来保存cx
datasg ends
​
code segment
 start:mov ax,datasg
 mov ds,ax
 mov bx,0

 mov cx,4
 s0:mov ds:[40H],cx          ;使用定义的字ds:[40H]来临时保存cx的值
 mov si,0
 mov cx,3
 s:mov al,[bx+si]
 and al,11011111b
 mov [bx+si],al

 inc si
 loop s

 add bx,16
 mov cx,ds:[40H]          ;在这里再恢复cx的值
 loop s0

 mov ax,4c00h
 int 21h

codesg ends
end start 

多定义一个字,也就是说,使用ds:[40H]来存放cx的值。

但是,上面的方法还是很麻烦,因为如果需要保存多个数据的时候,必须要记住数据存放到了哪个单元,容易混乱,所以更好的方法是使用栈

最终改进的程序:

assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
 db 'ibm       '
 db 'dec       '
 db 'dos       '
 db 'vax       '
 dw 0          ;定义一个字,用来保存cx
datasg ends
​
stacksg segment
 dw 0,0,0,0,0,0,0,0  ;定义一个栈段,容量为16个字节
stacksg segment
​
code segment
 start:mov ax,stackag
 mov ss,ax
 mov sp,16
 mov ax,datasg
 mov ds,ax
 mov bx,0

 mov cx,4
 s0:push cx      ;使用定义的栈临时保存cx的值 
 mov si,0
 mov cx,3
 s:mov al,[bx+si]
 and al,11011111b
 mov [bx+si],al

 inc si
 loop s

 add bx,16
 pop cx      ;在这里再恢复cx的值 
 loop s0

 mov ax,4c00h
 int 21h

codesg ends
end start 

7.9问题

问题:[bx+si+idata]的灵活运用

编程,将datasg段中每个单词的前四个字母改为大写字母

assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
 dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment
 db '1.display       '
 db '2.brows         '
 db '3.replace       '
 db '4.modify        '
datasg ends
code segment
 start:......
codesg ends
end start

分析:

其中定义的字符串在内存中的存放是这样的:
寻址方式的灵活运用(问题7.6,7.7,7.9)_第3张图片
3.png

由于数据是连续存放的,可以将这四个字符串看作一个4行16列的二维数组,按照要求,需要修改每个单词的前4个字母,即二维数组的每一行的3~6列。需要进行4*4的二重循环,用变量R定位行,常量3定位每行要修改的起始列,变量C定位相对于起始列的要修改的列,

首先使用R定位第一行,循环修改R行的3+C列

然后再用R定位到下一行,再次循环修改R行的3+C列

使用bx来做变量,定位每行的起始地址,用si定位要修改的列,用[bx+3+si]的方式来对目标单元进行寻址。

代码:

assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
 dw 0,0,0,0,0,0,0,0
stacksg ends
​
datasg segment
 db '1.display       '
 db '2.brows         '
 db '3.replace       '
 db '4.modify        '
datasg ends
​
code segment
 start:mov ax,stacksg
 mov ss,ax
 mov sp,16          ;让CPU知道和栈段挂钩
 mov ax,datasg
 mov ds,ax          ;让CPU知道和ds挂钩
 mov bx,0

 mov cx,4
 s0:push cx          ;用来保存cx的值
 mov si,0          ;定义列
 mov cx,4
 s:mov al,[bx+si+3]  ;这里是定位到每个要索引的字母,每行总共有四个字母
 and al,11011111b
 mov [bx+si+3],al
 inc si          ;使它指向同一行的下一个字母
 loop s

 add bx,16
 pop cx
 loop s0

 mov ax,4c00h
 int 21h

codesg ends
end start

你可能感兴趣的:(寻址方式的灵活运用(问题7.6,7.7,7.9))