汇编语言替换(&)、文本(<>)、字符(!)、展开(%)运算符简述

< 上一页实例:矩阵行求和 宏函数下一页 >

下述四个汇编运算符使得宏更加灵活:

& 替换运算符
<> 文字文本运算符
! 文字字符运算符
% 展开运算符

替换运算符(&)

替换运算符(&)解析对宏参数名的有歧义的引用。宏 mShowRegister 显示了一个 32 位寄存器的名称和十六进制的内容。示例调用如下:

.code
mShowRegister ECX

下面是调用 mShowRegister 产生的示例输出:

ECX=00000101

在宏内可以定义包含寄存器名的字符串变量:

mShowRegister MACRO regName
.data
tempStr BYTE "regName=",0

但是预处理程序会认为 regName 是字符串文本的一部分,因此,不会将其替换为传递给宏的实参值。相反,如果添加了 & 运算符,它就会强制预处理程序在字符串文本中插入宏实参 ( 如 ECX)。下面展示的是如何定义 tempStr:

mShowRegister MACRO regName
.data
tempStr BYTE "&regName=",0

展开运算符(%)

展开运算符(%)展开文本宏并将常量表达式转换为文本形式。有几种方法实现该功能。若使用的是 TEXTEQU,% 运算符就计算常量表达式,再把结果转换为整数。

在下面的例子中,% 运算符计算表达式 (5+count),并返回整数 15 ( 以文本形式 ):

count = 10
sumVal TEXTEQU %(5 + count)            ;="15"

如果宏请求的实参是整数常量,% 运算符就能使程序具有传递一个整数表达式的灵活性。计算这个表达式得到结果值,然后将这个值传递给宏。例如,调用 mGotoxyConst 时,计算表达式的结果分别为 50 和 7:

mGotoxyConst %(5 * 10), %(3 + 4)

预处理程序将产生如下语句:

1  push edx
1  mov dh,7
1  mov dl,50
1  call Gotoxy
1  pop edx

% 在一行的首位

当展开运算符 (%) 是一行源代码的第一个字符时,它指示预处理程序展开该行上的所有文本宏和宏函数。比如,假设想在汇编时将数组大小显示在屏幕上。下面的尝试不会产生期望的结果:

.data
array DWORD 1,2,3,4,5,6,7,8
.code
ECHO The array contains (SIZEOF array) bytes
ECHO The array contains %(SIZEOF array) bytes

屏幕输出没什么用:

The array contains (SIZEOF array) bytes
The array contains %(SIZEOF array) bytes

反之,如果用 TEXTEQU 编写包含 (SIZEOF array) 的文本宏,那么该宏就可以展开为之后的代码行:

TempStr TEXTEQU %(SIZEOF array)
%   ECHO The array contains TempStr bytes

产生的输出如下所示:

The array contains 32 bytes

显示行号

下面的宏 Mul32 将它前两个实参相乘,乘积由第三个实参返回。其形参可以是寄存器、内存操作数和立即数 ( 乘积除外 ):
Mul32 MACRO op1, op2, product
    IFIDNI <op2>,<EAX>%
        LINENUM TEXTEQU %(@LINE)
        ECHO ----------------------------------------------
%       ECHO * Error on line LINENUM: EAX cannot be the second
        ECHO * argument when invoking the MUL32 macro.
        ECHO ----------------------------------------------
    EXITM
    ENDIF
    push eax
    mov eax,op1
    mul op2
    mov product,eax
    pop eax
ENDM
Mul32 要检查的一个重要要求是:EAX 不能作为第二个实参。这个宏有趣的地方是,它显示的是其调用者的行号,这样更加易于追踪并解决问题。首先定义文本宏 LINENUM,它引用的 @LINE 是一个预先定义的汇编运算符,其功能为返回当前源代码行的编号:

LINENUM TEXTEQU % ((@LINE)

接着,在含有 ECHO 语句的代码行第一列上的展开运算符 (%) 使得 LINENUM 被展开:

%   ECHO * Error on line LINENUM: EAX cannot be the second

假设如下宏调用发生在程序的 40 行:

MUL32 val1, eax,val3

那么,汇编时将显示如下信息:

文字文本运算符(<>)

文字文本(literal-text)运算符(<>)把一个或多个字符和符号组合成一个文字文本,以防止预处理程序把列表中的成员解释为独立的参数。

在字符串含有特殊字符时该运算符非常有用,比如逗号、百分号(%)、和号(&)以及分号(;),这些符号既可以被解释为分隔符,又可以被解释为其他的运算符。例如,之前给岀的宏 mWrite 接收一个字符串文本作为其唯一的实参。如果传递的字符串如下所示,预处理程序就会将其解释为3个独立的实参:

mWrite "Line three", 0dh, 0ah

第一个逗号后面的文本会被丢弃,因为宏只需要一个实参。然而,如果用文字文本运算 符将字符串括起来,那么预处理程序就会把尖括号内所有的文本当作一个宏实参:

mWrite <"Line three", 0dh, 0ah>

文字字符运算符(!)

构造文字字符(literal-character)运算符(!)的目的与文字文本运算符的几乎完全一样:强制预处理程序把预先定义的运算符当作普通的字符。在下面的 TEXTEQU 定义中,运算符 ! 可以防止符号 > 被当作文本分隔符:

BadYValue TEXTEQU <Warning: Y-coordinate is !> 24>

警告信息示例

下面的例子有助于说明运算符 %、& 和 ! 是如何工作的。假设已经定义了符号 BadYValue。现在创建一个宏 ShowWarning,接收一个用引号括起来的文本实参,并将其传递给宏 mWrite。注意替换(&)运算符的用法:

ShowWarning MACRO message
    mWrite "&message"
ENDM

然后调用 ShowWarning,把表达式 %BadYValue 传递给它。% 运算符计算(解析) BadYValue,并生成与之等价的字符串:

.code
ShowWarning %BadYValue

正如所期望的,程序运行并显示警告信息:

Warning: Y-coordinate is > 24

< 上一页实例:矩阵行求和 宏函数下一页 >

爱面试的程序媛,一个分享面试经验的公众号。跟着站长一起学习,每天都有进步。

通俗易懂,深入浅出,定时分享程序员面试的那点事。

面试如何造火箭?工作如何拧螺丝?都在这个公号哦。

扫描二维码关注公众号,免费领取价值 1000 元的求职面试资料(限时免费)!

当你决定关注「爱面试的程序媛」,你已然超越了90%的程序员!

爱面试的程序媛二维码
微信扫描二维码关注