在 32 位模式下,AAA ( 加法后的 ASCII 调整 ) 指令调整 ADD 或 ADC 指令的二进制运算结果。设两个 ASCII 数字相加,其二进制结果存放在 AL 中,则 AAA 将 AL 转换为两个非压缩十进制数字存入 AH 和 AL。一旦成为非压缩格式,通过将 AH 和 AL 与 30h 进 OR 运算,很容易就能把它们转换为 ASCII 码。
下例展示了如何用 AAA 指令正确地实现 ASCII 数字 8 加 2。在执行加法之前,必须把 AH 清零,否则它将影响 AAA 执行的结果。最后一条指令将 AH 和 AL 转换为 ASCII 数字:
mov ah, 0
mov al, '8' ; AX = 0038h
add al, '2' ; AX = 006Ah
aaa ; AX = 0100h (结果进行 ASCII 调整)
or ax, 3030h ; AX = 3130h ='10' (转换为 ASCH 码)
现在来查看一个过程,其功能为实现包含了隐含小数点的 ASCII 十进制数值相加。由于每次数字相加的进位标志位都要传递到更高位,因此,过程的实现要比想象的更复杂一些。下面的伪代码中,acc 代表的是一个 8 位的累加寄存器:
进位值必须总是被转换为 ASCII 码。将进位值与第一个操作数相加时,就需要用 AAA 来调整结果。程序清单如下:
; ASCII Addition (ASCII_add.asm)
; 对有隐含固定小数点的串执行 ASCII 运算。
INCLUDE Irvine32.inc
DECIMAL_OFFSET = 5 ; 距离右侧的偏移量
.data
decimal_one BYTE "100123456789765" ; 1001234567.89765
decimal_two BYTE "900402076502015" ; 9004020765.02015
sum BYTE (SIZEOF decimal_one + 1) DUP(0),0
.code
main PROC
; 从最后一个数字开始
mov esi,SIZEOF decimal_one - 1
mov edi,SIZEOF decimal_one
mov ecx,SIZEOF decimal_one
mov bh,0 ; 进位值清零
L1: mov ah,0 ; 执行加法前清除AH
mov al,decimal_one[esi] ; 取第一个数字
add al,bh ; 加上之前的进位值
aaa ; 调整和数 (AH = 进位值)
mov bh,ah ; 将进位保存到 carry1
or bh,30h ; 将其转化为 ASCII 码
add al,decimal_two[esi] ; 加第二个数字
aaa ; 调整和数 (AH = 进位值)
or bh,ah ; 将进位值 carry1 进行 OR 运算
or bh,30h ; 将其转换为 ASCII 码
or al,30h ; 将 AL 转换为 ASCII 码
mov sum[edi],al ; 将 AL 保存到 sum
dec esi ; 后退一个数字
dec edi
loop L1
mov sum[edi],bh ; 保存最后的进位值
; 显示和数字符串
mov edx,OFFSET sum
call WriteString
call Crlf
exit
main ENDP
END main
程序输出如下所示,和数没有显示十进制小数点: