汇编学习笔记整理之循环结构
鉴于之前学习代码的时候总是因为没有在课后整理笔记并且重新复习而导致知识点掌握不熟练的后果,现在将每次学习的笔记整理至csdn博客中。以便更好的督促自己学习
一、前览
汇编语言的循环结构程序设计可以通过循环伪指令实现,也可以通过循环指令或转移
指令实现。循环伪指令汇编后转换成相应的循环指令或转移指令。
二、.while伪指令
1.语法格式
.while伪指令的特点是先判断后执行,主要用于循环次数不确定的情况下。当条件为真时进入循环,条件为假时跳出循环执行后续指令。
.while 条件表达式
指令系列 ;可插入[.break [.if 退出条件]] ; [.continue [.if 结束当前循环条件]]
.endw
2. 典例
1)键盘输入若干个复数,分别求其模,最后再求所有模之和并显示(保留1位小数)。
模r=sqrt(a2+b2)
运行后若输入:
3.0 4.0
1.0 1.0
6.0 8.0
则结果输出:
16.4
.386
.model flat, stdcall
option casemap :none
include kernel32.inc
includelib kernel32.lib
includelib msvcrt.lib ;引用C库文件
printf PROTO C:ptr sbyte,:vararg ;C语言printf函数原型声明
scanf PROTO C:ptr sbyte,:vararg ;C语言scanf函数原型声明
;*【*/
.data
x qword ?
y qword ?
a qword ?
b qword ?
p qword ?
q qword ?
sum qword 0.0
fmt db '%lf%lf',0
fmt1 db '%.1lf',0
.code
start:
fld sum
invoke scanf,addr fmt,addr x,addr y
.while EAX==2 ;判断当输入两个数时进入循环
fld x
FMUL x
fstp a
fld y
FMUL y
fstp b
fld a
FADD b
FSQRT
fstp p
FADD p
invoke scanf,addr fmt,addr x,addr y
.endw
fstp sum
invoke printf,addr fmt1,sum
ret
end start
;*】*/
2)编写求1+2+3+…+n和的程序(整数n由键盘输入且n>1)。
运行后若输入:10
则结果输出:1+…+10=55
运行后若输入:100
则结果输出:1+…+100=5050
;*【*/
.386
.model flat, stdcall
option casemap :none
include kernel32.inc
includelib kernel32.lib
includelib msvcrt.lib ;引用C库文件
printf PROTO C:ptr sbyte,:vararg ;C语言printf函数原型声明
scanf PROTO C:ptr sbyte,:vararg ;C语言scanf函数原型声明
.data
fmt db '%d',0
fmt1 db '1+...+%d=%d',0
x dword ?
.code
start:
invoke scanf,addr fmt,addr x
MOV ECX,1
MOV EAX,0
.while ecx<=x
add eax,ecx
Inc ecx
.endw
invoke printf,addr fmt1,x,eax
ret
end start
;*】*/
3)输入一串字符串,求字符串的长度并输出
运行后若输入:abc
则结果输出:3
方法一:使用while循环判断输入的串是否到结尾‘0’处,在判断的过程中使用寄存器ecx累加,最后输出的ecx的值即为字符串的长度
;*【*/
.386 ;选择的处理器
.model flat, stdcall
option casemap:none ;指明标识符大小写敏感
include kernel32.inc ;要引用的头文件
includelib kernel32.lib ;要引用的库文件
includelib msvcrt.lib ;引用C库文件
scanf PROTO C:DWORD,:vararg ;C语言scanf函数原型声明
printf PROTO C:DWORD,:vararg;C语言printf函数原型声明
.data ;⑤数据段
s db 80 DUP(0)
fmt db '%s',0
fmt1 db '%d',0
.code
start:
invoke scanf,addr fmt,addr s
MOV ECX,0
.while s[ECX]!=0 ;这里的0指的不是数字意义上的0,指的是字符串的最后一个位:/0
INC ECX
.endw
invoke printf,addr fmt1,ECX
ret
end start
;*】*/
方法二:使用.repeat伪指令
在初始时用变址寄存器 edi 指向目的串 S 的前一字符即 S-1, 用 AL 寄存器保存要查找的数值 0,用 ecx 寄存器保存要比较的字符个数,用.repeat 伪指
令实现重复比较,直到目的数据与 AL 的值相等或比较完(ecx=0),再根据退出时edi的值(地 址)与目的串的首地址之差值求出串长度。
;*【*/
.386 ;选择的处理器
.model flat, stdcall
option casemap:none ;指明标识符大小写敏感
include kernel32.inc ;要引用的头文件
includelib kernel32.lib ;要引用的库文件
includelib msvcrt.lib ;引用C库文件
scanf PROTO C:DWORD,:vararg ;C语言scanf函数原型声明
printf PROTO C:DWORD,:vararg;C语言printf函数原型声明
.data ;⑤数据段
s db 80 DUP(0)
fmt db '%s',0
fmt1 db '%d',0
.code
start:
invoke scanf,addr fmt,addr s
mov AL,0
lea edi,s-1
mov ecx,80
.repeat
INC edi
.untilcxz [edi]==AL
lea eax,s
Sub edi,eax
invoke printf,addr fmt1,edi
ret
end start
;*】*/
三、.repeat伪指令
1.语法格式
.repeat伪指令的特点是先执行后判断
程序执行到.repeat 循环时,首先执行一遍循环体中的指令,然后计算并判断
条件表达式的值是否为真,直到条件表达式的值为真时,才退出循环,否则返回.repeat伪指令处重新执行循环。
格式一:
.repeat
指令系列 ;可插入[.break [.if 退出条件]] ; [.continue [.if 结束当前循环条件]]
.until 条件表达式
格式二:
.repeat
指令系列 ;可插入[.break [.if 退出条件]] ; [.continue [.if 结束当前循环条件]]
.untilcxz [条件表达式]