写在前面:本文通过宏定义计算二进制的八位中的奇偶(即八位0、1中1的个数),通过call方法计算另外的八位,实现最后计算十六位二进制数奇偶校验!
本文使用的编译器为emu8086,下载地址
怎么计算八位二进制中的1的个数呢?
我这里用的方法是通过一个二进制数与一个二进制数 ,形如 0000 0001,即可实现掩码操作,获取某一位上二进制的值,将这些1累加起来,就可以得到二进制数中的1的个数,即可实现奇偶校验的结果!
以下为对0000 1001 进行二进制奇偶校验 ,获取值的操作为循环右移shr
利用宏实现前八位的计算
简单说一下宏调用和子程序的区别:
子程序在程序执行期间调用,只占用自身大小的一段空间。
(必须到子程序的IP,好处是节省内存,效率高,但是因为要保存返回地址,转向地址,时间长,适合长代码,频繁调用的)
宏调用,在汇编期间被展开,调用一次展开一次。
宏汇编通常使用 macro 、endm这一对宏汇编伪指令来做到,格式如下:
宏名 macro [形参表]
宏定义体
endm
宏名在同一源程序中,保持唯一,宏可以带形式参数表;可选的形参表给出了宏定义中用到的形式参数(哑元,简称为形参),之间用逗号相隔。
宏定义中的注释如果是用;;分割的,则后边宏展开不再出现该注释。
宏调用的格式为:
伪指令格式:宏名[实参表]
本例中计算ah中的代码如下:
countah macro ;使用
push dx
push cx
mov ch, 8h
mov cl, 0h
mov bh, 00000001
loopa:
mov dh, ah
and dh, bh
shr dh, cl
adc bl, dh
rol bh, 1
inc cl
dec ch
jnz loopa
pop cx
pop dx
endm
使用call方法计算al中的二进制奇偶
由于call方法之前进行过简述,此处不再多讲。
代码如下:
countal:proc
push dx
push cx
mov ch, 8h
mov cl, 0h
mov bh, 00000001
loopb:
mov dh, al
and dh, bh
shr dh, cl
adc bl, dh
rol bh, 1
inc cl
dec ch
jnz loopb
pop cx
pop dx
ret
endp
整体代码如下:
; multi-segment executable file template.
data segment
; add your data here!
data1 db 0h
num db 00000001
pkey db "The number of 1 in ax is "
count dw 0h
db " .","$"
ends
stack segment
dw 128 dup(0)
ends
code segment
countah macro ;使用
push dx
push cx
mov ch, 8h
mov cl, 0h
mov bh, 00000001
loopa:
mov dh, ah
and dh, bh
shr dh, cl
adc bl, dh
rol bh, 1
inc cl
dec ch
jnz loopa
pop cx
pop dx
endm
start:
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
; add your code here
mov bl, 0
countah
call countal
mov al, bl
mov ah, al
and ax, 0f00fH
mov cl, 4
shr ah, cl
or ax, 3030H
xchg ah,al
mov count, ax
lea dx, pkey
mov ah, 9
int 21h ; output string at ds:dx
; wait for any key....
mov ah, 1
int 21h
mov ax, 4c00h ; exit to operating system.
int 21h
ends
countal:proc
push dx
push cx
mov ch, 8h
mov cl, 0h
mov bh, 00000001
loopb:
mov dh, al
and dh, bh
shr dh, cl
adc bl, dh
rol bh, 1
inc cl
dec ch
jnz loopb
pop cx
pop dx
ret
endp
end start ; set entry point and stop the assembler.
本例中只进行了计算ax中的二进制奇偶性,可以自行拓展为输入变量,计算其二进制奇偶性。