王爽汇编第三版课程设计1
课程设计一般都是比较综合的题目,考你对之前书上大部分知识点的掌握,而课程设计1在我看来,考的有寻址、打印、子程序设计方面。
我做这题,是按列来打印的,即先打印年份,然后打印年收入,然后打印雇员,最后再打印平均工资。这题我做了很久,期间我差点放弃,一度怀疑自己的智商有问题。后面我把标志寄存器这章看完了,总感觉心里不舒服,没错,就是因为这个课程设计没做出来!
我想过用之前的那个,将这些数据存到table数据段中(就是第7章的那题,要求把这些数据按照一定格式存到table段),然后按行读取,或按列读取。奈何我沿着这个思路做不出来,但是不代表在座的各位也做不出来。程序的设计是灵活多变的,一种程序有N种设计也是很正常的,重要的是找到适合你的那一个,那一个不一定是最好的,但是你理解自己的设计,那么它对你来说,就是最好的。
首先年份可以直接打印,因为是字符串,其次是另外三种类别,需要用到一个不会溢出的除法子程序,具体实现代码请看除法子程序。
然后还需要一个将十六进制转换成十进制的子程序,这个子程序通过连除10来得到余数,依次压栈,打印的时候再依次出栈,这样就可以正序地打印数字了。
最后还需要一个计算一个数字的位数的子程序,将其赋值给CX,这样我们就可以用循环来打印数字。这些就是主要的部分了,接下来放上代码:
assume ds:data,ss:stack,cs:codesg
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983','1984','1985','1986','1987','1988','1989','1990','1991','1992','1993','1994','1995'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226,11542,14430,15257,17800
data ends
stack segment
dw 16 dup(0)
stack ends
codesg segment
start:
mov ax,data
mov ds,ax
mov bx,0
mov ax,stack
mov ss,ax
mov sp,32
mov ax,0b800h
mov es,ax
mov si,0
mov di,640
mov cx,21
;首先把年份全部打印出来
printYear:
push cx
mov cx,4
print_year:
mov al,ds:[bx+si]
mov es:[di],al
mov al,7
mov es:[di+1],al
inc si
add di,2
loop print_year
sub di,8
add di,160
pop cx
loop printYear
;接下来开始打印年收入
mov cx,21
mov si,0
mov bx,84
mov di,680 ;每列的间距是32个字 从第5行开始打印 160*4+8+32
printAnnualIncome:
push cx
mov ax,ds:[bx+si]
mov dx,ds:[bx+si+2]
call dtoc
add si,4
mov al,2
mul byte ptr ss:[0]
sub di,ax
add di,160
pop cx
loop printAnnualIncome
;接下来打印雇员
mov cx,21
mov si,0
mov bx,168
mov di,720
printEmployee:
push cx
mov ax,ds:[bx+si]
mov dx,0
call dtoc
add si,2
mov al,2
mul byte ptr ss:[0]
sub di,ax
add di,160
pop cx
loop printEmployee
;最后打印平均工资
mov cx,21
mov si,0
mov bx,84
mov di,756
printAveragewage:
push cx
mov ax,ds:[bx+si]
mov dx,ds:[bx+si+2]
push ax ;这一段是将si的值/2,因为雇员是word,每次只应该加2,而dword应该每次加4
push dx
push si
mov ax,si
mov dx,2
div dl
mov si,ax
mov cx,ds:[bx+si+84]
pop si
pop dx
pop ax
call divdw ;用年收入/雇员 商低位AX 高位DX 再转换成十进制
call dtoc
add si,4
mov al,2
mul byte ptr ss:[0]
sub di,ax
add di,160
pop cx
loop printAveragewage
mov ax,4c00h
int 21h
dtoc:
mov cx,10
call divdw ;得到的商低位在AX,高位在DX,余数在CX
add cx,30h ;把余数加上30h得到十进制数
push cx
mov cx,ax ;把商低位给CX,用JCXZ判断是否已完成
jcxz ok
jmp dtoc
ok:
;开始计算cx的值
mov cx,32
sub cx,sp
mov ax,cx
mov cl,2
div cl
sub ax,2
mov cx,ax
;计算完 开始打印
mov ss:[0],cx ;设为计数器 计算数的位数
jmp print
print:
pop ax
mov es:[di],al
mov al,7
mov es:[di+1],al
add di,2
dec cx
jcxz over
jmp print
over:
ret
divdw:
push ax ;将被除数低16位进栈 因为等下要用到
mov ax,dx ;我们要做32位除法 所以要清空高16位寄存器
mov dx,0
div cx ;得到的商在ax 余数在dx
mov ss:[0],ax ;暂时保存商 商为式子的商的高16位 这里的商不用左移16位 因为他是保存在另外一个寄存器的
pop ax ;将ax出栈 因为等下要用到
div cx ;现在把dx看做高16位 ax看做低16位 我们做除法 除数是cx
;现在我们得到了一个商,它为式子的低16位 保存在AX中 余数保存在DX中
mov cx,dx ;把余数赋值给CX
mov dx,ss:[0] ;把高16位得数取出来 赋值给dx
ret ;关键的思想是 把rem(H/N)看为一个数的高16位 那么就不用除65536 这样就不会出现乘法溢出了
codesg ends
end start
运行效果图:
还是那句话,适合自己的方法才是最好的,我想这也是这本书为什么作者没有给出参考答案的原因吧,这样给了读者更大的思考空间,而不是一味地填鸭式教育。
上一篇: 挑战408——数据结构(19)——树的遍历(先序,中序,后序)
下一篇: 寄存器---汇编学习笔记