![d1a5d7dce67c2f7e1eec8e44680c91d7.png](https://i-blog.csdnimg.cn/blog_migrate/cab0ce6d8710119be6cb396a42edeafb.png)
利用宏实现1+2+3…+100 并显示结果:5050
stack segment
dw 521 dup(?) ;申请栈空间 为保护变量使用
stack ends
data segment
string db 'hell,everybody',0dh,0ah,'$'
table equ this byte ;存储单元别名操作符THIS:它为同一存储单元取另一别名-table,该别名可具有其自身的数据属性,但其段地址和偏移量是不变的
count=1
rept 100
db count ;重复汇编
count=count+1
endm
data ends
code segment
assume cs:code,ds:data,ss:stack
start:
mov ax,data
mov ds,ax
mov dx,offset string ;显示 字符串 hello world
mov ah,9
int 21h
mov ax,0
mov si,offset table
mov cx,100
;开始循环累加
sum:
add al,[si]
adc ah,0
inc si
loop sum
mov dx,0
mov cx,1000
div cx
push dx ;这里很重要 利用栈保护dx的值 不然 后面add dl,30h后 会破坏原来dx的值 而dx的值是余数 不可以被破坏
mov dl,al
add dl,30h
mov ah,02h
int 21h
pop dx ;恢复dx的值
;提取百位
mov ax,dx
mov cl,100
div cl
mov dl,al
add dl,30h
mov ch,ah
mov ah,02h
int 21h
;提取十位
mov al,ch
mov ah,0
mov cl,10
div cl
mov ch,ah
mov dl,al
add dl,30h
mov ah,02h
int 21h
mov dl,ch
add dl,30h
mov ah,02
int 21h
jieshu:
mov ax,4c00h
int 21h
code ends
end start
结果
![4b6b82bb807c6bdaef80f9dc690e1e52.png](https://i-blog.csdnimg.cn/blog_migrate/22fb75eb8e7719a81c0a8e556b7bc5b0.png)
注意:
table equ this byte
这句代码的意思:对于下方宏定义的100个存储了1–100的地址 我们必须有个变量指向其首地址 这样我们才可以通过首地址获得第一个变量及以后的变量
在代码段,table所指向的就是存储元素为1的地址。
举例:
存储单元别名操作符THIS:它为同一存储单元取另一别名,该别名可具有其自身的数据属性,但其段地址和偏移量是不变的。
操作符THIS的一般格式为: THIS 数据类型
其中:数据类型就是常用的数据类型:BYTE、WORD、DWORD、NEAR和FAR等。
如:
LABC EQU THIS BYTE
LABD DW 4321H, 2255H
这样就给同一片存储单元LABD,取了二个具有不同数据类型的变量名。于是,在指令中,引用不同的变量名,就使用其不同的数据属性:
- 如果引用变量名LABD,是按“字”属性来访问;
- 如果引用变量名LABC,是按“字节”属性来访问。
如此一来,指令“MOV AL,LABC
”和“MOV AL,byte ptr LABD
”是等效的,所不同的是:当以“字节”属性访问LABD存储区时,不必使用强制属性符PTR,而改用“字节”属性变量LABC即可
易错:
mov dx,0
mov cx,1000
div cx
push dx ;这里很重要 利用栈保护dx的值 不然 后面add dl,30h后 会破坏原来dx的值 而dx的值是余数 不可以被破坏
mov dl,al
add dl,30h
mov ah,02h
int 21h
pop dx ;恢复dx的值
这里最容易错的地方,就是不用栈存储原来dx的值,因为dx中存储的是除以1000之后的余数,但是为了显示一个字符,我们 add dl,30h 这样一来,会破坏dx的值 ,导致后面出错。
为了避免这种情况的发生,我们应该对dx的值进行保护,这里可以利用栈实现,先入栈dx,后需要的时候再出栈即可。
2.进行循环递加后,其实ax中存储的值是13ba,是十六进制,其实汇编都是对十六进制进行处理,在除以1000的时候,我们认为是5050/1000=5,但是计算机却是先把1000转换为十六进制后,在进行除法,但是,结果还是5.和我们需要的一致。为了显示在电脑上,其实就是利用ASICC输出。5的ASICC是35,所以需要加30h
3.在循环递加时,有人会问,可以用下面这个式子吗?
sum:
add ax,[si]
inc si
loop sum
实验结果证明,不行
![32c2e0a2d3954b18906eb749ece3298c.png](https://i-blog.csdnimg.cn/blog_migrate/d6e8d00e98e0ed2fbbf1948a0667195f.jpeg)
利用单步调试可以看出,一开始加1,结果却是0201,不是我们希望的0001。这是因为偏移量为si的地址,存储的值1其实是在低八位,高八位不一定为0哦。所以用add al,[si]
4.对于为什么要进位?这是因为,我们所说的低八位、高八位,其实就是8位2进制数,最大就是11111111=255,而结果5050>255,所以必须利用进位存在ax中。
![1281fd04953fe4015ae9395940acd573.png](https://i-blog.csdnimg.cn/blog_migrate/8810e873d2d02a725b2a1e6703fcf894.png)