荣誉值:6
信誉值:0
注册日期:2008-05-13 20:29 |
首先我先说下思路(算上三个实验和这个课程设计,用了我两天时间,头都昏了,呵呵,这个代码是我最终感觉不错的。):我看到论坛中,大家都直接将年份以字符串形式定义在data段中,可我认为,此年份数据是已知的数据,对于此课程设计来说直接定义字符串似乎有点不妥吧,所以我也将我的代码发来大家看看。
1、在数据段中,将四种数据定义为四个数组,分别以0结尾。将ds:[bx]来定位数据段中的数据,从而不必去考虑数据有多长,只要注意是双字还是单字?是单字:add bx,2(加上0占的空间)就指向了下一个数组;是双字:add bx,4就指向了下一个数组。同时我在数据段开头用了16个字节的空间来暂存将每一个数据参数转换成的字符串信息,用si来定位。
2、因为有双字数据,有单字数据,所以我定义了两个子程序sdword和sword,分别来进行数据参数为双字和单字时的调用。
3、在主程序当中直接定义行参数dh,列参数dl和颜色参数cl,调用sdword或是sword就可以了。其它操作,比如转换操作,显示操作等由sdword,sword来调用相应的子程序就可以了。
assume cs:code
stack segment
dw 24 dup(0)
stack ends
data segment
db 16 dup(0) ;字符串暂存处。
dw 1975,1976,1977,1978,1979,1980,1981,1982
dw 1983,1984,1985,1986,1987,1988,1989,1990
dw 1991,1992,1993,1994,1995,0
dd 16,22,382,1356,2390,8000,16000,24486
dd 50065,97479,140417,197514,345980,590827,803530,1183000
dd 1843000,2759000,3753000,4649000,5937000,0
dw 3,7,9,13,28,38,130,220
dw 476,778,1001,1442,2258,2793,4037,5635
dw 8226,11542,14430,15257,17800,0
dw 5,3,42,104,85,210,123,111
dw 105,125,140,136,153,211,199,209
dw 224,239,260,304,333,0
data ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,48
mov ax,data
mov ds,ax
mov dh,4
mov dl,1
add bx,16
call s_word ;定义年份显示的地址,其为字型数据。
add bx,2
mov dh,4
mov dl,7 ;定义总收入显示的地址,其为双字型数据。
call s_dword
add bx,4
mov dh,4
mov dl,16
call s_word ;定义人员显示的地址,其为字型数据。
add bx,2
mov dh,4
mov dl,23
call s_word ;定义人均收入显示的地址,其为字型数据。
mov ax,4c00h
int 21h ;上面的这些传递参数。
s_word: push bp
push dx
push cx
push ax
push dx
push si
s_word_s: mov bp,dx ;将将要显示的地址暂存,以免和下面的指令冲突。定义一个字型参数,十进制显示。
mov ax,[bx] ;对于字形数据的操作。
mov dx,0
mov cx,ax
jcxz s_word_ret
mov si,0 ;此做为一个子程序来调用。
call dtoc ;转换十进制操作。
mov dx,bp
mov cl,00001111b
mov si,0
call show_str ;显示操作
add bx,2
inc dh ;指向下一行。
jmp short s_word_s
s_word_ret: pop si
pop dx
pop ax
pop cx
pop dx
pop bp
ret
s_dword: push dx
push bp
push ax
push cx
push si
s_dword_s: mov bp,dx ;定义一个双字型参数,十进制显示出来。
mov ax,[bx]
mov dx,[bx].2 ;对于双字形数据的操作。
mov cx,ax
add cx,dx ;防止(dx)<>0,(ax)=0时跳过循环了。
jcxz s_dword_ret
mov si,0
call dtoc ;转换十进制操作。
mov dx,bp
mov cl,00001111b
mov si,0
call show_str ;显示操作
add bx,4
inc dh
jmp short s_dword_s
s_dword_ret: pop si
pop cx
pop ax
pop bp
pop dx
ret
dtoc: push ax
push bx
push cx
push dx
mov bx,0 ;将bx置为0,来做后面的出栈计数器
dt_s: mov cx,10 ;设置将要转换的进制,此处是十进制
call divdw ;调用divdw来进行除法运算。
add cx,30h ;转换为字符形式
push cx ;将字符压栈。
inc bx ;计数器加一。
mov cx,ax
jcxz dt_s0
inc cx
loop dt_s
dt_s0: mov cx,bx ;将记录的入栈次数送入cx
dec bx ;将计数器bx减一操作。
pop [si]
inc si
loop dt_s0
pop dx
pop cx
pop bx
pop ax
ret
divdw: push bx
mov bx,ax ;将低16位暂存
mov ax,dx
mov dx,0
div cx ;进行高16位除法运算
push ax ;将高16计算的结果暂存
mov ax,bx ;将低16位送入ax中,好进行低16位的除法运算。
div cx ;进行低16位的除法运算(dx中存有高16位的余数),计算后(ax)为返回值。
mov cx,dx ;将余数返回。
pop dx ;将运算总结果的高16位返回。
pop bx
ret ;子程序返回
show_str: push ax
push bx
push cx
push dx
push si ;将用到寄存器入栈暂存。
mov ax,0b800h
mov es,ax ;刚开始此命令我放在主程序当中,最后看到论坛中放在子程序当中,感觉挺好,我就改进了。
mov al,160
mul dh
add dl,dl
mov dh,0
add ax,dx ;此三步定位显示的地址,dh,dl在这里做参数好似坐标轴一样。
mov bx,ax ;将显示地址送入bx寄存器。
mov ah,cl ;将颜色参数送入字符中。
mov si,0
mov ch,0
sh_s: mov al,[si] ;将字符串送入al中。
mov cl,al
jcxz sh_s0
mov es:[bx],ax ;将字符串显示出来。
inc cl ;防止ds:[si]刚好为01时,loop无法循环。
inc si ;指向下一个字符
add bx,2 ;将显示单元指向下一个位置。
loop sh_s
sh_s0: pop si
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
我还是很模糊那个sword和sdword子程序是否可以通用??
望高手分析下。 | | |