[Chapter 10] - [课程设计1]

mac2024-04-02  31

思路

创建1个临时区域,用于存放dtoc转换后的字符串 区域命名为temp考虑到容量要足够容纳 “十进制待转换数字” 的每一位转换后的ASCII,对比原始数据后,用16个内存单元足可容纳此区域的每个字符串均用1个值为00的单元结尾,此功能由dtoc实现 主程序循环21次,每次对每个字段的其中1个数据进行处理,包含的动作内容为: 将data中 年份 字段中1个数据(dword型),传递到temp,并手动补末尾0将data中 总收入 字段中1个数据(dword型),通过mov给AX和DX,再调用dtoc,转换为末尾为0的字符串,存储到temp。再调用show_str从temp处读取字符串并传递到显示缓冲区将data中 雇员 字段中1个数据(word型),通过mov给AX和DX,再调用dtoc,转换为末尾为0的字符串,存储到temp。再调用show_str从temp处读取字符串并传递到显示缓冲区先计算 平均收入 字段的值,将此值通过mov给AX和DX,再调用dtoc,转换为末尾为0的字符串,存储到temp。再调用show_str从temp处读取字符串并传递到显示缓冲区 (额外注意): 栈的空间大小,要设置足够大,否则过程中会出现向栈顶方向溢出,从而覆盖temp甚至data的情况。本次使用了64个单元主程序要跳转到循环开始的距离,越过了loop的范围,所以改用jcxz配合jmp near ptr

关于此思路存在的问题

过于繁琐,例如,对每个数据的处理都要调用show_str。替代方案完全可以先将每个字段中的1个数据,组成1个组合,然后21行构成table段。最终只调用一次show_str从table中读取即可因为这是我想到的其中一种思路,所以先实现它,目的是为了练习

最终效果: 代码:

;课程设计1 P211 assume cs:code,ds:data,ss:stack ;ds data segment ;年份:dword, ds:[0] db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995' ;年收入:dword, ds:[84] dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 dd 345980,590827,803530,1183000,1843000,2759000,3753000,46749000,5937000 ;雇员数:word,ds:[168] dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 dw 11542,14430,15257,17800 data ends ;es temp segment db 16 dup(0);16个单元容纳任何一个数转换出来的ASCII字符串,绰绰有余 temp ends ;ss。注意空间要足够 stack segment stack db 64 dup (0) stack ends code segment start: mov ax,data mov ds,ax mov ax,temp mov es,ax mov ax,stack mov ss,ax mov sp,64 ;第一部分:data - temp - buffer mov bx,0;年份 年收入 index mov bp,0;雇员数 平均收入 index mov si,0;temp index ;show_str参数设置,显示属性cl,位置行dl在循环中单独赋值 mov dh,0 mov cx,21 transfer_start: push cx ;过程中会多次修改dx值,而dh位于dx中,先保存 push dx ;后面的dtoc,show_str运行后都不会改变CX的值。只有divdw会改变CX,但它又位于dtoc内部,dtoc会恢复CX mov cl,2 ;(1)处理年份 mov ax,[bx] mov es:[0],ax mov ax,[bx+2] mov es:[2],ax mov al,0 mov es:[4],al push ds mov ax,temp mov ds,ax mov dl,0 call show_str pop ds ;(2)处理总收入 mov ax,[bx+84] mov dx,[bx+84+2] call dtoc push ds mov ax,temp mov ds,ax mov dh,ss:[61] mov dl,20 call show_str pop ds ;(3)处理雇员 mov ax,ds:[bp+168] mov dx,0 call dtoc push ds mov ax,temp mov ds,ax mov dh,ss:[61] mov dl,40 call show_str pop ds ;(4)处理平均收入 mov ax,[bx+84] mov dx,[bx+84+2] div word ptr ds:[bp+168];此后步,AX存平均收入 ;构建由AX,DX组成的被除数 mov dx,0 call dtoc push ds mov ax,temp mov ds,ax mov dh,ss:[61] mov dl,60 call show_str pop ds add bx,4 add bp,2 pop dx inc dh pop cx dec cx ;没有使用loop,因为超出跳转范围 jcxz transfer_end jmp near ptr transfer_start transfer_end: mov ax,4c00h int 21h ;第二部分:3个子程序 ;名称:dtoc ;功能:将DEC数字转换为字符串 ;参数:AX和DX表示待转换的DEC数字,向es:[si]写入字符串 ;返回:无 dtoc: push ax push bx push cx push dx push si ;末尾0。此处不能用AX,因为是被除数的组成部分 mov cx,0 push cx dtoc_push: mov cx,10 call divdw ;转换过程中得到的每个余数,都一一对应DEC数值中的某位(包括0),都需要入栈 add cx,30h push cx ;判断商是否为0,分别对AX和DX进行判断。与余数是否为0没有关系,即使余数为0也要入栈,因为DEC数值某位有0很正常 mov cx,dx jcxz next jmp short dtoc_push next: mov cx,ax jcxz dtoc_pop jmp short dtoc_push dtoc_pop: pop cx mov es:[si],cl jcxz dtoc_end inc si jmp short dtoc_pop dtoc_end: pop si pop dx pop cx pop bx pop ax ret ;名称:divdw ;功能:将dword类型的被除数,除以word类型除数,防止溢出 ;接受参数:AX和DX构成被除数,CX为除数 ;返回:AX存储商的低16位,DX存储商的高16位,CX存储余数 divdw: push bx ;int(H/N) push ax mov ax,dx mov dx,0 div cx mov bx,ax ;(rem(H/N)*65536+L)/N pop ax div cx mov cx,dx mov dx,bx pop bx ret ;名称:show_str ;功能:将字符串显示到屏幕上 ;接受参数:从ds:[si]读取字符串,写入buffer的位置由dh(行),dl(列)给出,cl指出显示属性 ;返回:无 show_str: push ax push cx push dx push si push di push es mov ax,0b800h mov es,ax ;计算di,dh*160+dl*2 mov al,160 mul dh ;因用dx相加计算dl*2,需将dh清零 mov dh,0 add dx,dx add ax,dx mov di,ax ;cl将用于jcxz,属性值由al代持 mov al,cl ;copy source to buffer show_copy: mov ch,0 mov cl,[si] jcxz show_end mov es:[di],cl mov es:[di+1],al inc si add di,2 jmp short show_copy show_end: pop es pop di pop si pop dx pop cx pop ax ret code ends end start
最新回复(0)