📄 宏.txt
字号:
FOR reg,
xor reg, reg
ENDM
ENDM
不过要注意的是VARARG修饰的参数必须是参数中的最后一个。
让宏返回一个值
宏过程和宏函数的区别在于是否有返回值。当然这里的返回值和执行期的函数的返回值也是很不一样的。执行期的函数是通过eax来传递返回值的。而这里,也不过是直接替换而已。返回值的语法是这样的:
EXITM textitem
一个宏函数可以有多个EXITM,就像C中的函数可以有多个return一样。不过必须返回值一致。看一个简单的例子
Who MACRO
EXITM
ENDM
%echo Who()
结果是显示taowen。如果把()去掉,则显示的是who。可见对于宏函数的调用一定要加上 ()。而调用宏过程则不能加()。看一个有趣的例子:
Who MACRO temp
%echo temp
ENDM
Who()
显示的结果是()。说明()被当作传递给宏过程的参数了。
可以比较随意的使用返回值,可以把返回值这么用。
Who MACRO
EXITM
ENDM
Who() TEXTEQU
这样就定义了汇编期文本变量,值为genius。可见宏函数可以用在任何文本变量可以出现的地方,很多地方可以把高级语言中函数中那些类推过来。
局部变量
宏中可以有局部变量,它看起来像局部的,实际上不过是一些名称上的小技巧。
对于局部变量有两点事实:1、在函数外无法访问,2、在对函数的不同次的调用中其值应该不受前次调用的影响。
TestMacro MACRO
LOCAL LocalVar
%echo LocalVar
LocalVar TEXTEQU
ENDM
如果对于函数的调用每次之间会互相影响,那么这么调用:
TestMacro
TestMacro
第一次会产生一个未定义变量的错误,而第二次就会输出Hello。事实上,由于LocalVar 是LOCAL的。所以两次都是未定义错误。这个就体现了局部变量的多次调用的独立性。
下面我们来揭穿局部变量的底牌。不用我多叙述,直接看看这个你就明白了:
TestMacro MACRO
LOCAL LocalVar
echo LocalVar
ENDM
TestMacro
TestMacro
输出的结果是:??0000与??0001。这个就是局部变量的实际名字。局部变量就是通过怪怪的名字让外部无法访问(你不知道它是什么名字),然后在每次展开同一个宏的时候用不同的名字替换局部变量的名字,使得多次调用之间不会互相影响。
其实你可以试验一下这个:
??0000 TEXTEQU
TestMacro MACRO
LOCAL LocalVar
%echo LocalVar
ENDM
TestMacro
显示的结果是Hello,这样就在一个宏过程(函数)的外部访问了局部变量。
文本操作
MASM内置了两套文本操作功能,一个是宏函数,另一个是Directive。功能是一样的,但是提供了表达上的灵活性。
name CATSTR [[textitem1 [[, textitem2]] ...]]
name INSTR [[position,]] textitem1, textitem2
name SIZESTR textitem
name SUBSTR textitem, position [[, length]]
这一套是Directive,作用分别是:连接文本,查找子文本,获得文本长度,取子文本。
@CatStr( string1 [[, string2...]] )
@InStr( [[position]], string1, string2 )
@SizeStr( string )
@SubStr( string, position [[, length]] )
这一套是宏函数。用一个例子显示两套其实是一样的:
taowen TEXTEQU @CatStr(, )
%echo taowen
taowen CATSTR ,
%echo taowen
可以看到两个例子输出的都是He is genius。有两点需要注意:1、@CatStr这样的宏函数可以作为左值,被用来赋值。2、@CatStr这样的宏函数对于参数并不自动求值,当行为和你想的不一样的时候,加上%。
对于具体的使用不是很难,试验一下就可以知道了。一点就是第一个字符的索引是1,而不是C中的0。
%与求值
%可能是最难使用的语法了。一般就是行为和你想的不一样的时候,加上%试验一下。%与 <>与!等,构成了一团糟。
一般情况下,你不用%号。用%可以把数值变量转变为文本变量。可以用%号强制取出文本的值。比如:
Index = 0
NameT CATSTR , %Index
%NameT TEXTEQU
%echo Person0
先对Index用%就是把数值变成文本,第二个%就是把NameT变成Person0。这里也演示了一个产生变量名的很重要的技巧,只要把Index进行一些递增,就能够构建一个变量的数组了。
<>可以一定程度上放置被求值,不过大部分情况下由于文本宏的替换不受影响,所以仍然取到的是替换后的值。!用来取消符号原有的意思。比如:
Symbol CATSTR , ,
%echo Symbol
输出的结果是Go, Go。如果不加!则,号会导致错误。有趣的是如果你在第二个Go后面加上 !本来应该是Go, Go!。结果确实一个缺少右尖括号的错误,原来是!把>的原有意思变化了,不再表示结束了。如果你这样:
Symbol CATSTR , , >
%echo Symbol
得出的就是Go, Go>。看出来是怎么回事了吧。要产生!,就这么写:
Symbol CATSTR , ,
%echo Symbol
关于什么时候用<>什么时候不用,我的看法是最好能用<>就用<>。具体为什么,是因为能够加大适用范围。
在宏中进行循环
循环有四种:WHILE,REPEAT,FOR,FORC。语法如下:
WHILE expression
statements
ENDM
REPEAT expression
statements
ENDM
FOR parameter [[:REQ | :=default]] ,
statements
ENDM
FORC parameter,
statements
ENDM
WHILE与REPEAT从用法到效果是一样的,至少我认为是一样的。expression要求值为一个数值,可以用EQ(等于),LT(小于)这些判断Operator来比较数值。
I = 0
WHILE I LT 10
Temp TEXTEQU %I
%echo Temp
I = I + 1
ENDM
输出的结果就是0一直到9。
FOR与FORC是专门用途的循环,一个是用于取得一个参数列表中的各个参数,另一个是逐个取出一个字符串中的每个字符。各举两个例子就可以明白:
TestMacro MACRO params:VARARG
FOR param,
%echo param
ENDM
ENDM
TestMacro arg1, arg2, arg3
显示的结果是arg1然后是arg2然后是arg3。
FORC char,
%echo char
ENDM
分别显示的是H和e和l和l和o。
在宏中进行判断
判断很简单了,不过有很多种IF,IFDEF,IFIDN,IFE,IFNDEF,IFDIF。使用上没有什么值得注意的都比较简单。分别是判断数值,判断符号是否定义,判断两个文本是否一致。
关于宏还有定义在宏中的宏,OPATTR, SIZEOF, LENGTHOF, 等等许多比较高级的东西。不过我相信有前面讲述的基础,这些东西的使用不过是查查手册的事情。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -