汇编的一些坑以及部分上机题目的实现

本文深入探讨8086汇编语言的实用编程技巧,包括字符串操作、数学运算、递归调用、数据类型转换及系统功能调用。通过具体代码示例,如字符串反转、数组处理、字符大小写转换等,详述了各种常见任务的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.存储器寻址时只能用BP,BX作为基址寄存器,DI,SI作为变址寄存器。
2.DOS系统2号中断功能(输出单字符)存在bug,会自动改变AL的值,故需进行入栈和出栈来对AX的内容进行保存。
3.用CALL指令进行递归时,PUSH一定要在CALL指令之前,否则栈顶最后存放的将是余数而不是地址,就无法递归了(具体见程序)。
4.循环条件自加时一定要注意位置,否则在条件判断时很容易就没法自加了……
5.length只在DUP返回重复数,其余时候都返回1
6.过程一定要有ret

代码样例:

1.十进制转2进制

;递归,缺点是不能自动去0,但是在做十进制输出时更优
change PROC
    xor cx,cx
    xor dx,dx
kkk:
	mov ah,0	;AH寄存器清0
	mov bl,2	
	div bl
	mov cl,al	
	mov dl,ah	;将余数送入DL
	mov ch,ah	
	or cl,ch	;若余数和商都为0,则位递归停止条件
	jz ppp		;返回 RET
	push dx		;将DX压入栈,保存余数
	call kkk	;递归,CALL存入断点
    pop dx		;恢复余数
    add dl,'0'
    mov ah,2
    int 21h
ppp:
	ret
change ENDP
;参考了老师的思想,循环实现,每次输出商
change2 PROC
	mov cx,7
kkk:
	mov ah,0
	push ax		;保存AX
	push cx		;保存CX
	mov al,1	;AL赋初值1
	mov bl,2	
ppp:
	mul bl		;AL乘2的CX次(依次从7-1,即结果为128-2)
	loop ppp
	mov bl,al	;将AL的值赋给BL
	pop cx		;取出CX的值,用于大循环
	pop ax		
	div bl		
	mov dl,al	;将商送入DL
	mov al,ah	;将余数作为下一次的被除数
	push ax
	add dl,'0'
	mov ah,2
	int 21h
	pop ax
	loop kkk
	
	push ax		
	mov dl,ah	;最后还应将最后的余数输出
	add dl,'0'
	mov ah,2
	int 21h
	pop ax
	
	ret
change2 ENDP

2.字符串反转

DATAS SEGMENT
buf db'abcde$'
len dw 6
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov ax,len
    mov bl,2
    div bl
    mov cl,al			;循环次数为len/2的商
    mov ch,0
    mov bp,offset buf
    mov si,len
    sub si,2			;将变址寄存器SI指向len-2,(从0开始,且不反转$)
    mov di,0			;变址寄存器DI指向0开始
kkk:
	mov al,[bp+di]		;变址寄存器寄存器不能减!
	mov ah,[bp+si]
	mov [bp+di],ah
	mov [bp+si],al
	inc di
	dec si
	loop kkk
    
    mov dx,offset buf
    mov ah,9
    int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

3.求一数组中的偶数和

START:
    MOV AX,DATAS
    MOV ES,AX
    
    mov bp,offset buf
    mov di,0
    mov cl,len
    mov ch,0
    mov dl,0
kkk:
	mov al,ES:[bp+di]
	mov ah,0
	mov bl,2
	div bl
	test ah,0ffh		;判断余数是否为0
	jnz ppp				;不为0的话跳转,不做加法
	add dl,ES:[bp+di]
ppp:
	inc di
	loop kkk
	
	mov bl,dl
	call showbyte
	   
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

4.找出字符串(20个DB)中字母A的位置并显示其位置(不一定只有1个)

DATAS SEGMENT
buf db 'A',2,4,'A','A'
len db 5
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
   	
   	mov bp,offset buf
   	mov di,0
   	mov cl,len
   	mov ch,0
kkk:
	mov al,[bp+di]
	cmp al,'A'
	jnz ppp			;比较AL与'A'的大小关系,如果不相等则进入ppp,DI加1后进入下一次循环
	push ax
	mov dx,di
	add dl,'0'
	mov ah,2
	int 21h
	pop ax
ppp:
	inc di
	loop kkk
   	
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

5.建立一个过程,将数据段中定义的组合BCD码数据一一显示出来

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
showBCD PROC
	push ax
	mov al,bl
	and al,0f0h			;取出高4位存入AL
	mov cx,4
kkk:					;让其右移4位,高位自动补0
	shr al,1
	loop kkk
	mov cl,10			
	mul cl				;AL乘10
	mov dl,bl
	and dl,0fh			;取出低4位
	add al,dl			;4*10+4位
	
	mov bl,al
	call showbyte
	pop ax
	ret
showBCD ENDP
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov bp,offset buf
    mov di,0
    mov cx,2
ppp:
    mov bl,[bp+di]
    push cx				;将CX推入栈,防止过程中对CX的影响
    call showBCD
    call showspace
    pop cx
    inc di
    loop ppp
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

6.利用DOS系统功能调用,将键盘输入的小写字母转换成大写字母显示,如果输入的不是小写字母则输出#号(本质就是一个if——else的思想)

DATAS SEGMENT
    ;此处输入数据段代码  
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov ah,8
    int 21h
    
    mov bl,'a'
    mov bh,'z'
    cmp al,bl
    jl quit
    cmp al,bh
    jg quit
    sub al,'a'-'A'
    mov dl,al
    jmp print		;AL的值装入后直接跳转到打印,防止进入quit
quit:
	mov dl,'#'
print:
	mov ah,2
	int 21h
	
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

7.计算数据段中定义的两个压缩BCD码的和并且显示(加法完了过后加上DAA,显示也要用BCD码的显示格式)

START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov bp,offset buf
    mov di,0
    mov al,[bp+di]
    inc di
    mov cl,[bp+di]
    add al,cl
    daa
    
    
   	mov bl,al
   	mov cl,al
   	and cl,0fh
   	and bl,0f0h
   	push cx
   	mov cx,4
kkk:
	shr bl,1
	loop kkk
	pop cx
	mov al,bl
	mov bl,10
	mul bl
	mov bl,al
	add bl,cl
	
	call showbyte
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

8.将数据段中定义的字符串数组用MOV指令拷贝到附加段的异名数组中,拷贝完成后将附加段中的字母一一显示
方法1:直接利用MOVSB指令进行DS到ES的传输

DATAS SEGMENT
buf1 db 'abcde$'
len1 db 6  
DATAS ENDS

EDATA SEGMENT
buf2 db 6 dup(?)
EDATA ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EDATA
START:
    MOV AX,DATAS
    MOV DS,AX
    MOV AX,EDATA
    MOV ES,AX
    
    mov si,offset buf1	;将DS段的buf1的有效地址送入SI
    mov di,offset buf2	;将ES段的buf2的有效地址送入DI
    mov cx,6			;一共6个字节
    cld					;正向送数据
    rep movsb
    
    mov dx,offset buf2	;
    mov ah,9
    int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

方法2:利用循环传输

DATAS SEGMENT
buf1 db 'awede$'
len1 db 6  
DATAS ENDS

EDATA SEGMENT
buf2 db 6 dup(?)
EDATA ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EDATA
START:
    MOV AX,DATAS
    MOV DS,AX
    MOV AX,EDATA
    MOV ES,AX
    
    mov bx,offset buf1	
    mov bp,offset buf2	
    mov si,0
    mov cx,6 
kkk:					;利用循环进行一位一位的传送
	mov al,[bx+si]
	mov [bp+si],al
	inc si
	loop kkk
    
    mov dx,offset buf2
    mov ah,9
    int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

9.利用DOS系统功能调用,将从键盘输入的2个数字的余数显示出来

DATAS SEGMENT
    ;此处输入数据段代码  
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov ah,1	;从键盘输入第一个数
    int 21h
    mov bl,al
    sub bl,'0'	;由于输入的是字符形式,需要减去'0'
    
    mov ah,1	;输入第二个数
    int 21h
    sub al,'0'
    
    push ax
    mov dl,10	;输出一个回车
    mov ah,2
    int 21h
    pop ax
    
    xchg bl,al
    mov ah,0
    div bl
    
    mov dl,ah
    add dl,'0'
    mov ah,2
    int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

10.建立一个过程,将数据段中定义的字符串大小写反置显示在显示器上,即大写变成小写,小写变成大写再显示

DATAS SEGMENT
buf db 'aEcd$'
len dw 5  
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
cov PROC 
    mov bp,offset buf
    mov cx,2
    mov di,0
    mov si,3
kkk:
	mov al,[bp+di]		;先把字符串的一位调入AL
	mov ah,[bp+si]		
	cmp al,'a'
	jge qqq				;如果大于等于a,则跳qqq
	add al,'a'-'A'		;小写转大写
	jmp www
qqq:					;大写转小写
	sub al,'a'-'A'
www:					;进入下一次比较
	cmp ah,'a'
	jge eee
	add ah,'a'-'A'
	jmp rrr
eee:
	sub ah,'a'-'A'
rrr:
	mov [bp+di],ah
	mov [bp+si],al
	inc di
	dec si
	loop kkk
	ret
cov ENDP
START:
    MOV AX,DATAS
    MOV DS,AX
   
	call cov
	
	mov dx,offset buf
	mov ah,9
	int 21h
	    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

11.寻找最后一个空格的位置

DATAS SEGMENT
buf db 'adf as de'
len dw 9
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov cx,len
    mov bp,offset buf
    mov di,0
kkk:
	mov al,[bp+di]
	cmp al,' '
	jnz ppp
	mov bx,di		;如果找到就覆盖
ppp:
	inc di
	loop kkk
	
	mov dl,bl
	add dl,'0'
	mov ah,2
	int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

12.一个字符串定义在DS内,一个定义在ES内,长度均为20。请找出第一个不同的字母的位置,并显示这两个字母

DATAS SEGMENT
buf1 db 'avdev'
DATAS ENDS

EDATA SEGMENT
buf2 db 'avdfe'
EDATA ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS,ES:EDATA
START:
    MOV AX,DATAS
    MOV DS,AX
    MOV AX,EDATA
    MOV ES,AX
    
    mov bp,offset buf1
    mov bx,offset buf2
    mov di,0
    mov cx,5
kkk:
	push cx
	mov al,[bp+di]
	mov cl,es:[bp+di]
	cmp al,cl
	jnz ppp
	inc di
ppp:
	pop cx
	loopnz kkk		;大坑,估计是编译器错了
	
	mov dx,di
	mov dh,0
	add dl,'0'
	mov ah,2
	int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START
DATAS SEGMENT
buf db 'AAABBBB'
len dw 7 
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov cx,len
    mov bp,offset buf
    mov di,0
    mov bx,0
kkk:
	mov al,[bp+di]
	cmp al,'A'
	jnz ppp
	inc bl
	jmp qqq
ppp:
	cmp al,'B'
	jnz qqq
	inc bh
qqq:
	inc di
	loop kkk
	
	sub bh,bl
	
	mov dl,bh
	add dl,'0'
	mov ah,2
	int 21h
    
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值