【王爽汇编】实验七 寻址方式在结构化数据访问中的应用

前言:上次我发了一篇实验八的博客,感觉手敲了题目然后自己分析然后再写代码这样的学习效果非常好,建议大家也可以参考这么做。这次呢,我又回过头来把实验七给补一补,这个也挺有难度,我觉得有必要进行知识的类比迁移,因为用汇编语言实现本实验的考点--结构体是比较困难的,但是c语言有专门的结构体数据类型(面向对象编程思想的鼻祖),从c语言类比过来,我们的思维难度就会小很多,剩下的就是对内存以及寄存器中的数据的传递的操作了。同样地,我会像上一篇文章那样,手敲这个题目,不仅能加深印象,还能精确读题,然后加上自己的分析和思考。

以下是王爽《汇编语言》第四版第172页的实验七:

Power idea公司从 1975年成立一直到1995年的基本情况如下:

公司收入情况
年份收入(千美元)雇员(人)人均收入(千美元)
1975163
1976227
19773829
1978135613
1979239028
1980800038
......
1995593700017800

下面的程序,已经定义好了这些数据:

assume cs:codesg
data segment
    db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
    db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
    db '1993','1994','1995'
    ;以上是表示21年的21个字符串

    dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
    dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
    ;以上是表示21年公司总收入的21个dword型数据

    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
    dw 11545,11430,15257,17800
    ;以上是表示21年公司雇员人数的21个word型数据

    data ends

table segment
    db 21 dup ('year summ ne ?? ')
table ends

解释:上面的是问题的背景说明和数据的定义,我们可以发现:公司收入/雇员=人均收入,这个公式非常好理解,那么这道题目也就非常好理解了,就是考验我们的除法的能力。

同时,我们可以看到table段作者已经给我们定义好了21个‘year summ ne ?? ’,这个东西我一开始也理解不了,后来看到21个字符串再看到前面的21个年份,就瞬间理解了:就是让我们用具体的数据覆盖掉原先的字符串,比如年份占用四个字节的空间(‘1975’),然后‘year’刚刚好就是四个字节,我们就是通过这样的刚刚好,把实际的数据存储到对应的位置中!

编程,将data段中的数据按如下格式写入到table栈中,并计算21年中的人均收入(取整),结果也按照下面的格式保存在table段中。

结构体表格
年份(4字节)空格收入(4字节)空格雇员数(2字节)空格人均收入空格
地址0  1  2  3  45  6  7  89A  B  DD  EF
table:0'1975'163?
table:10h'1976'227?
table:20h'1977'3829?
table:30h'1978'135613?
table:40h'1979'239028?
table:50h'1980'800038?
.......?
table:140h'1995'583700017800?

提示:可将data段中的数据看成是多个数组,而将table中的数据看成是一个结构型数据的数组,每个结构数据中包含多个数据项。可用bx定位每个结构型数据,用idata定位数据项,用si定位数组项中的每个元素,对于table中的数据的访问可采用[bx].idea和[bx].idea[si]的寻址方式。

注意:这个程序是到目前为止最复杂的程序,它几乎用到了我们以前学过的所有知识和编程技巧。所以这个程序是对我们从前学习的最好的时间总结。请认真完成。

说明:我们之前的猜测没有错,就是用具体的数据覆盖原先创建的字符串,并且这个过程非常类似c语言的结构体,连寻址方式都非常相似,我们可以通过如下的程序来简化思考。

以下是c语言结构体模拟程序:

#include <stdio.h>

struct table
{
	char year[4];
	int income;
	short int employees;
	short int per_income;
}tables[21];

int main(void)
{
	{
		tables[0].year[0] = '1';
		tables[0].year[1] = '9';
		tables[0].year[2] = '7';
		tables[0].year[3] = '5';
		tables[0].income = 16;
		tables[0].income = 3;
		tables[0].per_income = tables[0].income/tables[0].income;
	}
	return 0;
}

 我们可以看到,作者的提示里面的寻址方式和c语言的结构体变量的使用非常相似,比u如:[bx].idata[si]与tables[0].year[0],因为c语言的底层也是汇编,所以这二者之间也许真的有这样的联系。

在实际用汇编写的时候,我们不要忘记每个变量中间还夹杂这一个空格。

我们再对作者已经给我们写好了的程序进行分析:

1、DB:定义字节变量,每个变量占用1B的空间;

2、DW:定义字型变量,一个变量占用2B的空间;

3、DD:定义“double”类型变量,一个变量占用4B的空间。

我们再分析需要我们进行计算的人均收入:

1、div指令的用法:

(1)除数:有8位和16位,再一个寄存器或内存单元中;

(2)被除数:默认放在AX或DX和AX中。如果除数为8位,被除数则为16位,默认在AX中存放;如果除数是16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位;

(3)结果:如果除数为8位,则AL存储除法操作的商,AH存放除法操作的余数;如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。

在这里,为了简单描述这个比较麻烦的说法,我们可以自己规定一下:除数为8位的除法我叫它“小除法”,除数为16位的除法我叫它“大除法”,这样好记一点。

2、算法分析:

人均收入(2B) = 收入(4B) / 雇员(2B)

由这个公式可知:除数(雇员)占用2B即16位,我们要进行“大除法”。

也就是在计算人均收入时,因为收入是用DD声明的,所以我们可以把前面两个字节的内存单元里的内容放进DX,把后面两个字节的内存单元里的内容放进AX。

然后我们就可以开始写程序了

assume cs:codesg,ds:data,es:table,ss:stack
data segment
    db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
    db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
    db '1993','1994','1995'

    dd 16,22,383,1356,2390,8000,16000,24486,50065,97479,140417,197514
    dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2758,2793,4037,5635,8226
    dw 11542,11430,15227,17800
data ends

table segment
    db 21 DUP ('year summ ne ??')
table ends

stack segment
    dw 0,0,0
stack ends

codesg segment
start:  mov ax,data
        mov ds,ax
        mov ax,table
        mov es,ax
        mov ax,stack
        mov ss,ax
        mov ax,0
        mov bx,0
        mov bp,0
        mov dx,0
        mov si,0
        mov di,0
        mov cx,21
        ;以下处理年份
      s:
        push cx
        mov cx,4
          s0:mov al,[si+bx]
             mov es:[di+bx],al
             inc bx
          loop s0
        add di,16
        add si,4
        mov bx,0
        pop cx
      loop s
      ;以下处理收入
      mov si,0
      mov di,0
      mov bx,5
      mov cx,21
      s1:
        mov ax,[84+si]
        mov dx,[86+si]
        add si,4
        mov es:[di+bx],ax
        mov es:[di+2+bx],dx
        add di,16
      loop s1
      ;以下处理雇员
      mov si,0
      mov di,0
      mov bx,10
      mov cx,21
      s2:
        mov ax,[168+si]
        mov es:[di+bx],ax
        add si,2
        add di,16
      loop s2
      ;以下处理人均收入
      mov si,0
      mov di,0
      mov bp,0
      mov bx,0
      mov cx,21
      s3:
        mov ax,[84+si]
        mov dx,[86+si]
        add si,4
        mov bx,[168+di]
        add di,2
        div bx
        mov es:[bp+13],ax
        add bp,16
      loop s3

      mov ax,4c00h
      int 21h
codesg ends

end start

我尝试写了一段,但是失败了 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

April__Zhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值