第二章 软件设计技术
2-1 数据的存储方式
2-2 常用 DOS系统功能调用
2-3 BCD数的运算
2-4 补码与求补
2-5 进制的转换
2-6 数的排序片头 目录
2-1 数据的存储方式一,内存数据区中数据的存储存储方式 ----由低至高存放即,低位数存低单元,高位数存高单元 。
data segment
W DW 0012H
N DW 3456H
data ends
0000H
0001H
0002H
0003H
W
N
L
H
12
00
56
34
存储方式 ----由高至低存放(因为显示是由左至右)
即,高位数存低单元,低位数存高单元
data segment
OBUF DB 31H,32H,’A’,’$’
data ends
显示,12A 0000H
0001H
0002H
0003H
OBUF H
L
31
32
41
24 $
二,显示缓冲区中数据的存储回章首
2-2 常用 DOS系统功能调用表一,DOS系统功能调用调用号 功能 入口参数 出口参数
1 键入并显示 1个字符 字符的 ASCII码在 AL中
2 显示 1个字符 字符的 ASCII码置 DL
9 显示字符 串字符串首址置 DS,DX,
字符串以‘ $’结尾
(用户设置)
10 键入并显示字符串显示区首址置 DS,DX,
第一单元置允许键入的最大字符数(含一个回车符)
键入的实际字符数在第二单元,键入字符的 ASCII
码从第三单元开始存放,
以‘ 0D‘结尾(自动存放 |)
11 检查键盘有无键入 有,则 AL=FFH; 无,则AL=00H
DOS系统功能调用过程:
1.调用号 AH
2.输入参数 DS,DX
3.执行 INT 21H
4.分析处理出口参数
data segment
OBUF DB 31H,32H,‘A‘,‘$‘
data ends
主程序段:
MOV DX,OFFSET OBUF
MOV AH,9
INT 21H 显示,12A
字符首址 → DS,DX
功能号 → AH
0000H
0001H
0002H
0003H
OBUF H
L
31
32
41
24 $
显示缓冲区:
存放显示 字符串的 ASCII码一,9号功能调用
data segment
IBUF DB OFFH,0,255 DUP(?)
data ends
主程序段:
MOV DX,OFFSET IBUF
MOV AH,10
INT 21H
键入 并显示,1A
显示缓冲区首址 → DS,DX
功能号 → AH
0000H FF
0001H 00
0002H 00
0003H 00
0004H 00
IBUF
H
L
02
31
回车符开始存放键入 字符串的 ASCII码实际字符数最大字符数
41
0D
二,10号功能调用例:镜子程序:
数据段的定义:
data segment use16
obuf db '>',0dh,0ah,'$'
buf db 0ffh,0,255 dup(?)
data ends
程序段部分:
mov dx,offset obuf ; 显示提示符,>” 并回车换行
mov ah,9
int 21h
mov dx,offset ibuf ; 键入并显示字符串
mov ah,10
int 21h
mov bl,ibuf+1 ; 将,$,送键入字符串后
mov bh,0
mov ibuf[bx+2],'$'
mov dl,0ah ; 换行
mov ah,2
int 21h
mov dx,offset ibuf+2 ; 再显示键入的字符串
mov ah,9
int 21h
1,用汇编实现下列 C功能:
2-2习题,INT 21H系统功能调用
……
char s[16];
printf(―\nWhat is your name? ‖);
scanf(―%s‖,s);
printf(―\nMy name is %s\n‖,s);
……
不拘一格,灵活使用 1/2/9/10号
int 21h功能调用!
要求,1,独立编辑、编译、链接、调试;
2,编译成,EXE文件后,转到 DOS下运行,EXE程序,
看是否能否正确运行;若不能则独立调试、纠错;
3,根据 R/M窗口,在作业纸后面画出程序运行一次后的 详细的数据区存储映像图 (标好地址和存储值 );
4,完成上述内容后举手待查。
INT 21H系统功能调用
2,用汇编实现下列 C功能:
……
char s[16];
printf(―\nWhat is your name? ‖);
scanf(―%s‖,s);
printf(―\nMy name is %s\n‖,s);
……
不拘一格,灵活使用 1/2/9/10号
int 21h功能调用 !
要求,修改上述编写好的程序,将自己的名字 倒序输出,
如,What is your name?
YangMing
My name is WangHong
My name is gnoHgnaW
3,自己验证课本或手册中有关功能调用的程序例子。
编程步骤,(显示缓冲区应存放 显示 字符串的 ASCII 码 )
1) 拆字 ——将字节拆成低半字节和高半字节
2)变字符 ——将低半字节和高半字节分别加
30H转换成 ASCII 码字符
3)按从左至右的显示顺序将字符依次存入 显示缓冲区
4)采用 9号功能调用显示三,各种进制数的显示
1.十进制数的显示( 0—9)
例 2.2-1:将字变量 W中的 BCD数以十进制形式显示在屏幕上。
stack segment stack 'stack'
dw 32 dup (?)
stack ends
data segment
W DW 1234H
OBUF DB 4 DUP(?),'$'
data ends
code segment
0000H 34
0001H 12
0002H 00
0003H 00
0004H 00
0005H 00
0003H 24
W
OBUF
L
H
H
L
$
begin proc far
assume ss:stack,cs:code,ds:data
push ds
mov ax,0
push ax
mov ax,data
mov ds,ax
MOV CX,02
MOV DI,OFFSET W
MOV SI,OFFSET OBUF+3
0000H 34
0001H 12
0002H 00
0003H 00
0004H 00
0005H 00
0006H 24
W→ DI
OBUF+3
→ SI
L
H
H
L
$
OBUF
AB,MOV AL,BYTE PTR [DI] ; 将 [DI]→ AL
PUSH CX
MOV AH,AL
AND AL,0FH ; 屏蔽高四位,保留 低 四位
ADD AL,30H ; 变 ASCII 码字符
MOV [SI],AL ; 低 半字节 ASCII 码字符 →[ SI]
DEC SI
AND AH,0F0H ; 屏蔽低四位,保留 高 四位
MOV CL,4 ; 右 移四位
SHR AH,CL 将高四位 → 低四位
ADD AH,30H ; 变 ASCII 码字符
MOV [SI],AH ; 高 半字节 ASCII 码字符 →[ SI]
DEC SI
INC DI
POP CX
LOOP AB
MOV DX,OFFSET OBUF
MOV AH,9
INT 21H
ret
begin endp
code ends
end begin 显示,1234
0000H 34
0001H 12
0002H
0003H
0004H
0005H
0006H 24
W
OBUF
L
H
31
32
H
33
34 L
$
编程步骤,(显示缓冲区应存放显示 字符串的 ASCII 码)
1) 拆字 ——将字节拆成低半字节和高半字节
2) 变字符 ——将低半字节和高半字节分别转换成 ASCII 码字符
3)按 从左至右 的显示顺序将字符依次存入 显示缓冲区
4)采用 9号功能调用显示
≤9 加 30H
> 9 加 37H
2.十六进制数的显示( 0—FH)
例 2.2-2:将字变量 W中的十六进制数显示在屏幕上。
stack segment stack 'stack'
dw 32 dup (?)
stack ends
data segment
W DW 19AFH
OBUF DB 4 DUP(?),'H','$'
data ends
code segment
0000H AF
0001H 19
0002H 00
0003H 00
0004H 00
0005H 00
0006H 48
0007H 24
W
OBUF
L
H
H
L
H
$
begin proc far
assume ss:stack,cs:code,ds:data
push ds
mov ax,0
push ax
mov ax,data
mov ds,ax
MOV CX,02
MOV DI,OFFSET W
MOV SI,OFFSET OBUF+3
0000H AF
0001H 19
0002H 00
0003H 00
0004H 00
0005H 00
0006H 48
0007H 24
L
H
H
L
$
W( DI)
OBUF
OBUF+3
( SI)
H
NEXT,MOV AL,BYTE PTR [DI]
PUSH CX
MOV AH,AL
AND AL,0FH
CMP AL,0AH ; AL-0AH
JC NOADD7 ; < 0AH转 NOADD7(AL+30H)
ADD AL,7 ; ≥ 0AH,AL+7+30H
NOADD7:ADD AL,30H ; 低 半字节变为 ASCII 码字符
MOV [SI],AL ; 低 半字节 ASCII 码字符 →[ SI]
DEC SI
AND AH,0F0H
有借位转
MOV CL,4
SHR AH,CL
CMP AH,0AH
JC NOADD7H
ADD AH,7
NOADD7H:ADD AH,30H ; 高 半字节 ASCII变为码字符
MOV [SI],AH ; 高 半字节 ASCII 码字符 →[ SI]
DEC SI
INC DI
POP CX
0000H
0001H
0002H
0003H
0004H
0005H
0006H
0007H
W
OBUF
L
H
AF
19
31
39
H
41
46
48
L
H
LOOP NEXT
MOV DX,OFFSET OBUF
MOV AH,9
INT 21H
ret
begin endp
code ends
end begin
显示,19AFH
24 $
编程步骤,(显示缓冲区应存放显示 字符串的 ASCII 码 )
采用 2号功能调用 循环显示,
1) 拆字、变字符 ——将字节中的 每一位数分别加 30H:
左移 —将最高位移至进位位 CF中
带进位位左移 —将 CF中的数移至 AL
变字符 —AL+30H送至 DL
2)按 从左至右 的显示顺序将字符依次存入 显示缓冲区
3)采用 2号功能调用循环显示(注,每次显示后 AL应清零
3.二进制数的显示( 00000000—11111111B)
例 2.2-3:将字节变量 B中的十六进制数以二进制数形式显示在屏幕上。
stack segment stack 'stack'
dw 32 dup (?)
stack ends
data segment
B DB 12H
data ends
code segment
begin proc far
assume ss:stack,cs:code,ds:data
0000H 12 ( 00010010B)B
push ds
mov ax,0
push ax
mov ax,data
mov ds,ax
MOV CX,8
MOV BL,BYTE PTR B
NEXT,MOV DL,0
SHL BL,1 ; BL左移 1位,将最高位 → CF
RCL DL,1 ; DL带进位左移,CF中数移 → DL
ADD DL,30H ; 变字符
MOV AH,2
INT 21H
LOOP NEXT
MOV DL,’B’ ; 显示二进制标志符
MOV AH,2
INT 21H
ret
begin endp
code ends
end begin
显示,00010010B
回章首
2-3 BCD数的运算一,什么叫 BCD数
BCD数 ——二进制编码的十进制数,即用 十六进制形式表示的十进制数。
如,10H——十六进制表示 16
—— BCD数表示 10
1.压缩与非压缩的 BCD数压缩的 BCD数 —用八位二进制数表示两个十进制数位,即 一个字节表示两位十进制数 。
2.非压缩的 BCD数 —用八位二进制数表示一个十进制数位,即 一个字节表示一位十进制数 。
如,
十进制数 压缩的 BCD数 非压缩的 BCD数
1234 1234H 01020304H
(一千二百三十四 )
二,BCD的运算
BCD的运算 逢 10进 1
BCD进行运算后,运算指令后面要 紧跟 调整指令。
(紧跟是指调整指令与运算指令之间不得有改变标志位的指令)
1.BCD数加法调整指令
DAA--压缩 BCD数加法调整指令
AL & 0FH>9或 AF=1; AL+6→AL
AL & 0F0H>90或 CF=1; AL+60→AL
AAA—非压缩 BCD数加法调整指令
AL & 0FH>9或 AF=1;( AL+6) & 0FH→AL
AH+1→AH
AL & 0FH<9或 AF=0; AL & 0FH→AL
AH
特别注意,AAA调整指令执行前 AH的内容保留高字节 进位位标志保留低字节将半进位加入 AH有半进位无半进位 不变保留低字节 半进位位标志例 1:
MOV AX,3456H
ADD AL,AH ; AL=8AH( 56H+34H)
DAA ; AL=90H( 56+34)
例 2:
MOV AX,0806H
ADD AL,AH ; AX=080EH( 06H+08H)
MOV AH,0 ; AH清零,为调整作准备
AAA ; AH=0104H( 06+08)
DAS--压缩 BCD数减法调整指令
AL & 0FH>9或 AF=1; AL-6→AL
AL & 0F0H>90或 CF=1; AL-60→AL
AAS—非压缩 BCD数减法调整指令
AL & 0FH>9或 AF=1;( AL-6) & 0FH→AL
AH-1→AH
AL & 0FH<9或 AF=0; AL & 0FH→AL
AH
保留低字节 半进位位标志保留高字节 进位位标志有半进位保留低字节将半进位加入 AH
无半进位 不变
2.BCD数减法调整指令特别注意,AAS调整指令执行前 AH的内容例 1:
MOV AX,5634H
SUB AL,AH ; AL=DEH( 34H-56H),有借位
DAS ; AL=78( 134-56),保持借位例 2:
MOV AX,0806H
SUB AL,07H ; AX=08FFH( 06H-07H),有借位
AAA ; AX=0709( 06-07),保持借位
BCD数的加减运算只能做字节运算,不能做字运算。(因为调整指令只在 AL中进行)
压缩 BCD数对乘除法的结果不能进行调整
AAM----非压缩 BCD数乘法调整指令将 AL中的小于 64H(100)的二进制数进行十进制调整,在 AX中得到正确的非压缩 BCD数。
AL/0AH→
如:
MOV AL,63H ; 63H=99
AAM ; AX=0909H
AAD----非压缩 BCD数除法调整指令将 AX中的两位非压缩 BCD数变换为二进制数。 在做两位非压缩 BCD数除以一位非压缩 BCD数时,先将
3.非压缩 BCD数乘除法调整指令商 →AH
余数 → A
AX中的被除数调整为二进制数,然后再用二进制除法指令 DIV相除,保存 AH中的余数后,再用
AAM
指令把商变回为非压缩 BCD的数。
如:
MOV AX,0906H
MOV DL,06H
AAD ; AX=0006
DIV DL ; AL=10H,AH=0
MOV DL,AH ; 存余数
AAM ; AX=0106
加、减、乘法调整 ----在相应 运算 之 后 进行。
除法调整 ----在除法 运算 之 前 进行。
例 2.3-1:将两个 4位压缩的 BCD数相加(设不向更高位产生进位),并显示结果。
stack segment stack 'stack'
dw 32 dup(?)
stack ends
data segment
BCD1 DW 4563H
BCD2 DW 4987H
SUM DW?
SUMS DB 4 DUP(?),'$'
data ends
0000H 63
0001H 45
0002H 87
0003H 49
0004H 00
0005H 00
0006H 00
0007H 00
0008H 00
0009H 00
000AH 24
BCD1
BCD2
L
H
H
L
$
SUM
SUMS
L
H
code segment
begin proc far
assume ss:stack,cs:code,ds:data
push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
MOV AL,BYTE PTR BCD1
ADD AL,BYTE PTR BCD2 ; AL=63H+87H=EBH
DAA ; AL=50,CF=1
MOV BYTE PTR SUM,AL
MOV AL,BYTE PTR BCD1+1
ADC AL,BYTE PTR BCD2+1
DAA ; AL=45+49+1=95; CF=0
MOV BYTE PTR SUM+1,AL
MOV CX,02 ; 和的字节数
MOV DI,OFFSET SUM
MOV SI,OFFSET SUMS+3
0000H 63
0001H 45
0002H 87
0003H 49
0004H 00
0005H 00
0006H 00
0007H 00
0008H 00
0009H 00
000AH 24
BCD1
BCD2
L
H
H
L
$
SUM
→ DI 和
SUMS+3
→ SI
L
H
50
95
AB,MOV AL,BYTE PTR [DI] ; 和 → AL
PUSH CX
MOV AH,AL
AND AL,0FH
ADD AL,30H
MOV [SI],AL
DEC SI
AND AH,0F0H
MOV CL,4
SHR AH,CL
ADD AH,30H
MOV [SI],AH
DEC SI
INC DI
POP CX
LOOP AB
0000H 63
0001H 45
0002H 87
0003H 49
0004H 00
0005H 00
0006H 00
0007H 00
0008H 00
0009H
000AH
00
24
BCD1
BCD2
L
H
H
L
$
SUM
→ DI
SUMS+3
→ SI
L
H
50
95
39
35
35
30
将低半节变字符将高半节变字符
MOV DX,OFFSET SUMS
MOV AH,9
INT 21H
ret
begin endp
code ends
end begin
显示,9550
显示结果
stack segment stack 'stack'
dw 32 dup(?)
stack ends
data segment
IBUF DB 5,0,5 DUP(?)
W DW?
data ends
code segment
begin proc far
assume ss:stack,cs:code,ds:data
键入 4位数加上
‘ 0D’共 5个字节例 2.3-2:( P64,例 2.6)
将键入的 4位十进制数 (如 5,则键入 0005)以压缩 BCD数形式存入字变量 W中。
push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
MOV DX,OFFSET IBUF
MOV AH,10
INT 21H
MOV AX,WORD PTR IBUF+4
AND AX,0F0FH
MOV CL,4
0000H 05
0001H 04
0002H 00
0003H 00
0004H 00
0005H 00
0006H 0D
0007H 00
0008H 00
W
IBUF MAX数实际数
H
L
回车键入十进制数
1298
将两个 ASCII 码字符变为两位非压缩 BCD数键入数的 十 位 → AL=39
个 位 → AH=38
IBUF+4 39
38
31
32
SHL AL,CL ; 将十位移至 AL的高四位
OR AL,AH ; 十位和个位拼和在 AL中
MOV BYTE PTR W,AL
MOV AX,WORD PTR IBUF+2 ;AL=31,AH=32
AND AX,0F0FH
MOV CL,4
SHL AL,CL
OR AL,AH
MOV BYTE PTR W+1,AL
ret
begin endp
code ends
end begin
0000H 05
0001H 04
0002H 31
0003H 32
0004H 39
0005H 38
0006H 0D
0007H 00
0008H 00
W
IBUF MAX数实际数
H
L
回车
98
12
存 BCD数的千位和百位存 BCD数的十位和个位
IBUF+2
W+1
L
H
stck segment stack 'stack'
dw 32 dup(?)
stck ends
data segment
IBUF DB 5,0,5 DUP(?)
W DW?
data ends
code segment
begin proc far
assume ss:stck,cs:code,ds:data
例 2.3-3:
将键入的 4位十六进制数 (ASCII码字符 )以十六进制数形式存入字变量 W中。
键入 4位数加上
‘ 0D‘共 5个字节
push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
MOV DX,OFFSET IBUF
MOV AH,10
INT 21H
MOV SI,OFFSET IBUF+2 ; 键入字串的首址 → SI
MOV BL,[IBUF+1] ; 键入字串的个数 → BL
MOV CL,4 ; ASCII码字串的字节数
MOV AX,0
键入十六 进制数
12AB
0000H 05
0001H 04
0002H 31
0003H 32
0004H 41
0005H 42
0006H 0D
0007H 00
0008H 00
W
IBUF MAX数实际数
H
L
回车
AB
12
IBUF+2
L
H
NEXT,MOV DL,[SI]
CMP DL,41H ; 键入的 ASCII码字符与 ‘ 0A‘比较
JC NSUB7 ; <0AH转 NSUB7,减 30H
SUB DL,7 ; >0AH减 37H (-7-30H)
NSUB7,SUB DL,30H
SHL AX,CL ; 左移 4位,使 AL低四位 =0
OR AL,DL ; 将一位转换结果拼入 AL
INC SI
DEC BL
JNZ NEXT
MOV W,AX ; 存转换结果 ( 16进制数 )
ret
begin endp
code ends
end begin
一位 ASCII
码字符 →
16进制数
1.两个 4位非压缩型 BCD数相减 ( 设不向更高位产生借位 ),并以十进制形式显示结果 。 (参考 P80,例 3.1,注:非压缩型 BCD数变字符,可不拆字,直接加 30H。 )
2.两个字节数 ( 十六进制数 ) 相减 A-B送 D,
并以二进制形式显示结果 。
3.计算 X+Y送 Z( 字类型,设不向更高位产生进位 ),并以十六进制形式显示结果 。
2-3习题:
回章首
2-4 补码一,补码 与 求补 (NFG指令 )的区别负数的补码 ----保留 符号位,求反加 1。
负数求补( NEG) ----带 符号位一起求反加 1。
如:
-8的补码
( -8) 补码 =F8H
-8的求补( NEC)
( -8) 求补 =78H
10001000 -8
11110111 保留符号位
+ 1 求反加 1
11111000 F8H
10001000 -8
01110111 带符号位
+ 1 求反加 1
01111000 78H补码的绝对值
负数求补等于补码的绝对值如:
|-8| 求补
|-8|求补 =(8)求补
=F8H
( -8) 补码 =F8H
负数的绝对值求补等于其补码
10001000 -8
11110111 保留符号位
+ 1 求反加 1
11111000 F8H
00001000 8
11110111 带符号位
+ 1 求反加 1
11111000 F8H
二,负数的 绝对值求补 (NEG)
如:对补码 90H求补求 90H的真值:
( 90H) 补码 =F0H
=-112
(真值)
( 90H) 求补 =70H
=112
∣ 真值 ∣
负数的补码求补等于其真值的绝对值
10010000 90H
01101111 带符号位
+ 1 求反加 1
01110000 70H=112
10010000 -8
11101111 保留符号位
+ 1 求反加 1
11110000 F0H=-122
三,负数的 补码求补 (NEG)
回章首将存储器中 16位无符号二进制数转换成十进制数,并送显示器显示。( FFFFH∽ 0000H→ 65535∽ 0000)
W----存放 16位无符号 二进制数
OBUF—输出显示缓冲区( 10进制数 ASCII 码字符)
算法:
采用 除 10取余法,每除一次得到一位 十进制数,最先 得到 最低位,最后 得到 最高位 。
2-5 进制的转换一,二 (十六 )进制数 → 十进制数例 2.5-1,(P108,3.18)
W/10 → 余数( <10)—十进制数的 最低位

商 (≠0) 继续除 10 → ……

除到商 =0为止 —十进制的 最高位数据段:
W DW 0064H
OBUF DB 6 DUF(?)
0000H 64
0001H 00
0002H 00
0003H 00
0004H 00
0005H 00
0006H 00
0007H 24
W
OBUF
L
H
H
L
$OBUF+5
需显示的 最大数 65535的 ASCII
码字符占 5个字节,加上‘ $’,
∴ 显示缓冲区需留出 6个字节
16进制数主程序段:
MOV BX,OFFSET OBUF+5 ; 将?$‘存入显示区
MOV BYTE PTR [BX],?$? ; 的最后一个单元
MOV AX,W ; 0064H→AX
MOV CX,10 ; 做 32位除以 16位的除法故将 10送 CX
AGAIN,MOV DX,0 ; 无符号位扩展将 16位扩展为 32位
DIV CX ; AX/10,商 →AX ; 余数 →DX
ADD DL,30H ; 将余数( 10进制数)转换为 ASCII码
DEC BX ; 调整指针
MOV [BX],DL ; 将 10进制数 ASCII码字符 → 显示区
OR AX,AX ; 根据商是否为 0,设置 ZF
JNZ AGAIN ; 判商是否为 0,不为 0继续除以 10
MOV DX,BX ; 将显示区偏移量首址 →DX
MOV AH,9
INT 21H 显示,100( 10进制数)
16进制数 →10
进制数
ASCII
码将键入的补码数( 1∽4 位 16进制数),在显示器上以 10进制形式显示其真值。
( 键入 80,显示 128;
键入 FF80,显示 -128;
键入 FFFF,显示 -1;
键入 8000,显示 -32768; )
注意:以字变量数判正负例 2.5-2:(题解 P76,3.24)
编程要求:
编写主程序,接收键入的数字串,判别该数,若仅为回车符则结束程序运行,若为 16进制数则调用子程序,显示键入数的真值。
编程思路:
正数:(补码 =原码 ) 16进制 →10 进制负数,(补码求补 =∣ 真值 ∣ ) 16进制 →10 进制还原负号数据段:
IBUF DB 5,0,5 DUP(? )
OBUF DB 8 DUP(? ),0DH,
0A,‘$‘
0000H 05
0001H 00
0002H A3
0003H A2
0004H A1
0005H A0
0006H 0D
IBUF
MAX 字符数
OBUF
实际字符数键入 16进制补码数的 ASCII
码字符存 转换结果
( 10进制真值的 ASCII
码字符)
最小数为
-32768占 6个字节,加上
0AH换行符
,?=‘,共占
8个字节。
0007H 0A
0008H ‘ =’
0009H 00
000AH 00
000BH 00
000CH 00
000DH 00
000EH 00
000FH 0D
0010H 0A
0011H ‘ $’
主程序段:
push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
LOP1,MOV DX,OFFSET IBUF
MOV AH,10
INT 21H
CMP IBUF+2,0DH ; 键入的字符与回车符比较
JNZ LOP2 ; 若为回车符则结束程序
ret
LOP2,MOV AX,0
MOV CL,IBUF+1 ; 字串个数 → CL
MOV CH,0
MOV BX,2 ; BX=2指向字串首址
LOP3,MOV DL,IBUF[BX]
INC BX
SUB DL,30H
CMP DL,0AH
JC LOP4 ; 有借位位转,<0AH不减 7
SUB DL,7 ; ≥0AH 减 7
LOP4,PUSH CX
MOV CL,4
SHL AX,CL ; AX左移 4位,AL=0
OR AL,DL ; 将 DL的低 4位(余数)拼入 AL
将 16进制字符 串 →
16进制 数将 16进制数 → AX
POP CX
LOOP LOP3 ; CX≠0,继续转换
CALL QZ ; 调用子程序 QZ
JMP LOP1 ; 继续键入 16进制数
begin endp ; 主程序过程调用结束
QZ PROC ; 子程序与主程序过程并列放在同一代码段
AND AX,AX ; 判别 16进制的正负
PUSHF ; 保留符号位
JNS QZ1 ; 为正转 (去执行 16→10 进制程序)
NEG AX ; 为负求补 (负数的补码求补 =∣ 真值 ∣)
QZ1,MOV CX,10
MOV BX,OFFSET OBUF+7 ; BX指向 OBUF字串的最后一个单元
QZ2,MOV DX,0 ; 被除数 32位扩展
DIV CX ; 32位 /16位,余数 → DX; 商 → AX
ADD DL,30H ; 余数变字符
MOV [BX],DL ; 从最低位开始存放
DEC BX
OR AX,AX ; 判商是否位 0
JNZ QZ2 ; 不位 0转,商继续除 10
POPF ; 恢复符号位
JNS QZ3 ; 为正转
MOV BYTE PTR [BX],?-‘ ; 存 ‘ -’
DEC BX
QZ3,MOV BYTE PTR [BX],?=‘ ; 存 ‘ =’
DEC BX
无符号 16
进制数 →
10进制数
MOV BYTE PTR [BX],0AH ; 存 ‘ 换行 ’ 符
MOV DX,BX ; 从 BX处开始显示
MOV AH,9
INT 21H
RET ; 子程序返回(返回到主程序)
QZ ENDP ; 子程序过程调用结束
code ends
end begin
键入不带符号的 十进制数,将其转换成 十六进制数在显示器上显示。( 0∽65535→0000 H∽ FFFFH)
算法,((0*10+An-1)*10+An-2 )*10+…… )*10+A0
数据段:
IBUF DB 6,0,6 DUP(?)
W DW 0
OBUF DB 4 DUP(?),‘$‘
键入的 十进制 字数最多位占 5个字节,加上‘ 0D ‘,共计 6个字节二,十进制数 → 十六进制数例 2.5-3:(参考 P100,例 3.13去负数部分加显示 )
( 10→ 16)转换的结果
16进制数的 ASCII码字符
0000H 06
0001H 00
0002H 3A4
0003H 3A3
0004H 3A2
0005H 3A1
0006H 3A0
0007H 00
0008H 00
0009H 00
000AH 00
000BH 00
000CH 00
000DH 24
W
IBUF MAX 字符数
OBUF
实际字符数键入的 十进制 字串的 ASCII码
( A4—A0为 十进制数 )
转换的结果
( 10→ 16)
结果的 ASCII
码字符
( 16进制数)
内存映象图:
IBUF+ 2
$
主程序段:
MOV DX,OFFSET IBUF ; 键入 10进制数
MOV AH,10
INT 21H
MOV DL,0AH ; 换行
MOV AH,2
INT 21H
MOV CL,IBUF+1 ; 键入的个数 → CL
MOV CH,0
MOV SI,OFFSET IBUF+2 ; 指向键入的第一个字符
MOV AX,0 ; (0*10+An-1)*10+An-2 )*10+
AGAIN,MOV DX,10 ; …… )*10+A0
MUL DX
AND BYTE PTR [SI],0FH ;
ADD AL,[SI]
ADC AH,0
INC SI
LOOP AGAIN
MOV W,AX
MOV CX,02
MOV DI,OFFSET W
MOV SI,OFFSET OBUF+3
NEXT,MOV AL,BYTE PTR [DI]
10进制数 →16
进制 数 将 10进制数的 ASCII码
→ BCD数 ( 3An-1→ An-1)
……
将 16进制数 → W
以下为 16
进制显示程序
PUSH CX
MOV AH,AL
AND AL,0FH
CMP AL,0AH
JC NOADD7
ADD AL,7
NOADD7:ADD AL,30H
MOV [SI],AL
DEC SI
AND AH,0F0H
MOV CL,4
SHR AH,CL
CMP AH,0AH
JC NOADD7H
ADD AH,7
NOADD7H:ADD AH,30H
MOV [SI],AH
DEC SI
INC DI
POP CX
LOOP NEXT
MOV DX,OFFSET OBUF ; 显示 16进制数
MOV AH,9 ( 无符号数)
INT 21H
键入带符号的十进制数( -32768∽32767 ),
将其转换成十六进制数在显示器上显示 。
( -32768∽32767→8000 H∽7 FFFH)
编程思路:
1.为简化设计,正数则按习惯不键入 ‘ +’ 号,负数键入 ‘ -’ 号。
2.正数的转换同上题。( 10进制 →16 进制)
3.负数将 10进制的绝对值 →16 进制,再对其绝对值求补 =补码。( 负数的绝对值求补 =补码 )
例 2.5-4:(参考 P100,例 3.13加显示 )
数据段:
IBUF DB 7,0,7 DUP(?)
W DW 0
OBUF DB 4 DUP(?)
主程序段:
MOV DX,OFFSET IBUF ; 键入 10进制数
MOV AH,10
INT 21H
MOV DL,0AH ; 换行
MOV AH,2
INT 21H
键入的 十进制 字数最多位占 5个字节,加上‘ –
’、‘ 0D ‘,共计 7个字节( 10→ 16)转换的结果
16进制数的 ASCII码字符
MOV CL,IBUF+1 ; 键入字符的个数 → CL
MOV CH,0
MOV SI,OFFSET IBUF+2 ; 指向键入的第一个字
CMP BYTE PTR [SI],‘-’ ; 判是否为负数
PUSHF ; 保护零标志,供转换后再判别
JNE SININC ; 正数跳转,去 SININC( 10→ 16)
INC SI ; 跳过 ‘ -’ 号指向数字
DEC CX ; 实际字符数少 1( ‘ -’ )
SININC,MOV AX,0 ; (0*10+An-1)*10+An-2 )*10+
AGAIN,MOV DX,10 ; …… )*10+A0
MUL DX
AND BYTE PTR [SI],0FH ;
ADD AL,[SI]
ADC AH,0
INC SI
LOOP AGAIN
10进制数 →16
进制 数 将 10进制数的 ASCII码 → BCD
数( 3An-1→ An-1)
POPF ; 判断是否为负数时的零标志 ZF
JNZ NNEG ; 非 0即为正,则不求补
NEG AX ; 负数对其绝对值求补 =补码
NNEG,MOV W,AX ; 将 16进制数 → W
MOV CX,02
MOV DI,OFFSET W
MOV SI,OFFSET OBUF+3
NEXT,MOV AL,BYTE PTR [DI]
PUSH CX
MOV AH,AL
AND AL,0FH
CMP AL,0AH
JC NOADD7
以下为 16
进制显示程序
ADD AL,7
NOADD7,ADD AL,30H
MOV [SI],AL
DEC SI
AND AH,0F0H
MOV CL,4
SHR AH,CL
CMP AH,0AH
JC NOADD7H
ADD AH,7
NOADD7H:ADD AH,30H
MOV [SI],AH
DEC SI
INC DI
POP CX
LOOP NEXT
MOV DX,OFFSET OBUF ; 显示 16进制数
MOV AH,9 ( 符号数)
INT 21H
2-5习题:
1,从键盘输入一个无符号的十六进制数 (1∽ 4
位 ),在显示器上以十进制形式显示。
2.从键盘输入两个加数,求和并送显示器显示。
( 设两个加数及其和的位数相等,且最多为 4位,
均为无符号的十进制数)
回章首
2-6 数的排序排序问题可以采用逐一比较法或两两比较法 。
一,逐一比较法将 第 1个单元中的数与其后 N-1个单元中的数逐个 比较,每次比较后总是把 较大的数放在 一个寄存器中,经过 N-1次比较 后得到 N个数中的 最大数,存入第 1个单元 。接着将 第 2个单元中的数与其后 N-2个单元中的数逐个 比较,经过 N-2次比较后得到 N-1个数中的最大数(即 N个数中的 第 2大数 ),存入第 2个单元 。如此重复下去,当最后例 2.6-1,(P110,例 3.21 )
两个单元中的数比较之后,从大到小的顺序就排好了。
编制将字节变量 BUF存储区中存放的 N个无符号数排列的程序。
数据段:
BUF DB 12,23,15,28,37
COUNT EQU $-BUF
常数 等于 当前地址
COUNT=当前地址 -BUF首址
12 23 15 28 37 12 23 15 28
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
大( AL) 大( AL)
N=5 ↑ N=4 ↑
大( AL) 大( AL)
↑ 比较 N-2次 ↑
大( AL) ( AL) 第二大 → 第 2个单元比较 N-1次 ↑ ( BUF+1=28)
( AL) 最大 → 第 1个单元
( BUF+0=37)
……
12 15
比较 N-4次 ↑ ↑
( AL) 第四大 → 第 4个单元 ( BUF+3=15)
主程序段,( 逐一比较)
MOV SI,OFFSET BUF ; 字串首址 → SI
MOV DX,COUNT-1 ; 设置外循环计数指针
OUTSID,MOV CX,DX ; 设置内循环计数指针
PUSH SI ; 保护字串首址,(存大数的单元)
MOV AL,[SI]
INSIDE,INC SI
CMP AL,[SI]
JNC NEXCHG ; AL≥[SI] 不交换
XCHG [SI],AL ; AL<[SI]交换,(AL中始终为大数 )
NEXCHG,LOOP INSIDE ; 判内循环计数是否为 0,不为 0转
POP SI ; 恢复字串首址,(存大数的地址)
MOV [SI],AL ; 存大数
INC SI ; 修改字串首址
DEC DX ; 修改内、外循环计数指针
JNZ OUTSID ; 判外循环计数是否为 0,不为 0转二,两两比较法:
首先将第 1个单元中的数与第 2个单元中的数进行比较,若前者大于后者,两数不交换,反之则交换。 然后将第 2个单元中的数与第 3个单元中的数进行比较,按同样的原则决定是否交换。依次类推,最后将第 N-1个单元中的数与第 N个单元中的数进行比较,也按同样的原则决定是否交换如此经过 N-1次循环,N个数中的 最小数 到了 第 N
个单元 。再经过 N-2次上述同样的比较与交换的循环,N个数中的第 2小数到了第 N-1个单元。这例题同上:
数据段:
BUF DB 12,23,15,28,37
COUNT EQU $-BUF
12 23 15 28 37
↑ ↑↑ 小 ↑↑ 小 ↑↑ 小 ↑ N=5
前 >后不交换,↓ ↓
反之则交换。 …… …… 第 2小的数 最的小数总是将较小的 存 N-1单元 存 N单元数与后面单元的数比较。
样不断循环下去,最多经过 N-1次这样的循环,就可以将这 N个数按从大到小的顺序排好。
一般情况下,无须经过 N-1次外循环,就可以将这 N个单元中的数据按顺序排好。为了去掉不必要的外循环,可以设置一个标记,在 每次内循环开始时,该标记置,1” 。若 在内循环中发生过交换,
则修改该标记为 2。内循环结束以后,检查 该标记,
若不为,1”,表示内循环发生过交换,即 数的顺序未排好。继续进行外循环; 若为,1”,则表示数已按顺序排好,就结束外循环。
主程序段,( 两两比较)
MOV DX,COUNT-1 ; 设置外循环计数指针
MOV AH,1 ; 设置未交换标记
OUTSID,MOV SI,OFFSET BUF ; 字串首址 → SI
MOV CX,DX ; 设置内循环计数指针
INSIDE,MOV AL,[SI] ; [SI]→AL
INC SI ; SI+1
CMP AL,[SI] ; AL与 [SI]比较; ( [SI]与 [SI+1]比较)
JNC NEXCHG ; AL≥[SI] 不交换
XCHG [SI],AL ; AL<[SI]交换,(后一个单元始终为较小数 )
MOV [SI-1],AL ; 大数始终放在前一个单元
MOV AH,2 ; 置交换标记( AH=2)
NEXCHG,LOOP INSIDE ; 判内循环计数是否为 0,不为 0转
DEC DX ; 修改内循环计数指针
DEC AH ; AH-1( AH-1=1 交换过; AH-1=0 未交换 )
JNZ OUTSID ; 判是否进行过交换,是则继续循环回章首目录本章结束