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

思路

  • 创建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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值