前言:上次我发了一篇实验八的博客,感觉手敲了题目然后自己分析然后再写代码这样的学习效果非常好,建议大家也可以参考这么做。这次呢,我又回过头来把实验七给补一补,这个也挺有难度,我觉得有必要进行知识的类比迁移,因为用汇编语言实现本实验的考点--结构体是比较困难的,但是c语言有专门的结构体数据类型(面向对象编程思想的鼻祖),从c语言类比过来,我们的思维难度就会小很多,剩下的就是对内存以及寄存器中的数据的传递的操作了。同样地,我会像上一篇文章那样,手敲这个题目,不仅能加深印象,还能精确读题,然后加上自己的分析和思考。
以下是王爽《汇编语言》第四版第172页的实验七:
Power idea公司从 1975年成立一直到1995年的基本情况如下:
年份 | 收入(千美元) | 雇员(人) | 人均收入(千美元) |
1975 | 16 | 3 | ? |
1976 | 22 | 7 | ? |
1977 | 382 | 9 | ? |
1978 | 1356 | 13 | ? |
1979 | 2390 | 28 | ? |
1980 | 8000 | 38 | ? |
...... | |||
1995 | 5937000 | 17800 | ? |
下面的程序,已经定义好了这些数据:
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 | 4 | 5 6 7 8 | 9 | A B | D | D E | F |
table:0 | '1975' | 16 | 3 | ? | ||||
table:10h | '1976' | 22 | 7 | ? | ||||
table:20h | '1977' | 382 | 9 | ? | ||||
table:30h | '1978' | 1356 | 13 | ? | ||||
table:40h | '1979' | 2390 | 28 | ? | ||||
table:50h | '1980' | 8000 | 38 | ? | ||||
....... | ? | |||||||
table:140h | '1995' | 5837000 | 17800 | ? |
提示:可将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
我尝试写了一段,但是失败了