4.4. Поведение макросов
Имя макроса будет заменено его телом не только в том случае, если оно расположено в начале строки. Макрос может находиться в любом месте исходного текста, где допустима мнемоника инструкции (например, add
или mov
). Всё потому, что основное предназначение макросов — имитировать инструкции. Единственное исключение из этого правила — макросы недопустимы после префиксов инструкций (rep
).
Пример:
macro CheckErr
{
cmp eax, -1
jz error
}
call Something
a: CheckErr ; здесь макросу предшествует метка, всё Ок.
получим:
call Something
a: cmp eax,-1
jz error
Пример № 2:
macro stos0
{
mov al, 0
stosb
}
stos0 ;это место инструкции, будет замена.
here: stos0 ;это тоже место инструкции.
db stos0 ;здесь инструкции не место, замены не будет.
получим:
mov al, 0
stosb
here: mov al, 0
stosb
db stos0
Возможно переопределять (overload) инструкции посредством макросов. Так как препроцессор ничего об инструкциях не знает, он позволяет использовать мнемонику инструкции в качестве имени макроса:
macro pusha
{
push eax ebx ecx edx ebp esi edi
}
macro popa
{
pop edi esi ebp edx ecx ebx eax
}
эти 2 новые инструкции будут экономить по 4 байта в стеке, так как не сохраняют ESP
(правда, занимают побольше места, чем реальные инструкции:). Всё же, переопределение инструкций не всегда хорошая идея — кто-нибудь читая Ваш код может быть введён в заблуждение, если он не знает, что инструкция переопределена.
Также, возможно переопределять директивы ассемблера:
macro use32
{
align 4
use32
}
macro use16
{
align 2
use16
}
5. Макросы с фиксированным количеством аргументов
5.1. Макросы с одним аргументом
Макросы могут иметь аргумент. Аргумент представляет собой какой-либо идентификатор, который будет повсюду заменён в теле макроса тем, что будет указанно при использовании.
Синтаксис:
macro name argument { тело макроса }
Например:
macro add5 where
{
add where, 5
}
add5 ax
add5 [variable]
add5 ds
add5 ds+2
получим:
add ax, 5
add [variable], 5
add ds, 5 ;такой инструкции не существует
;но препроцессор это не волнует.
;ошибка появится на стадии ассемблирования.
add ds+2,5 ;ошибка синтаксиса, как и ранее
;определится при анализе синтаксиса (parsing).
(разумеется, комментарии в результате работы препроцессора не появятся:)
5.2. Макросы с несколькими аргументами
У макросов может быть несколько аргументов, разделённых запятыми,
macro movv where, what
{
push what
pop where
}
movv ax, bx
movv ds, es
movv [var1], [var2]
преобразуется в:
push bx
pop ax
push es
pop ds
push [var2]
pop [var1]
Если несколько аргументов имеют одно и тоже имя, то будет использован первый из них:).
Если при использовании макроса указать меньше аргументов, чем при определении, то значения неуказанных будет пустым:
macro pupush a1, a2, a3, a4
{
push a1 a2 a3 a4
pop a4 a3 a2 a1
}
pupush eax, dword [3]
получим:
push eax dword [3]
pop dword [3] eax
Если в аргументе макроса необходимо указать запятую, необходимо аргумент заключить в скобочки из символов <
и >
.
macro safe_declare name, what
{
if used name
name what
end if}
safe_declare var1, db 5
safe_declare array5,
safe_declare string,
получим:
if used var1
var1 db 5
end if
if used array5
array5 dd 1,2,3,4,5
end if
if used string
string db "привет, я просто строка",0
end if
Конечно же, можно использовать символы <
и >
и внутри тела макроса:
macro a arg {db arg}
macro b arg1,arg2 {a
b <1,1>,2
получим:
db 1,1,2,3
5.3. Директива LOCAL
Возможно, появится необходимость объявить метку внутри тела макроса:
macro pushstr string
{