call behind ; помещаем в стек адрес string и переходим к behind
db string, 0
behind:
}
но если использовать такой макрос 2 раза, то и метка behind
будет объявлена дважды, что приведёт к ошибке. Эта проблема решается объявлением локальной метки behind
. Это и делает директива LOCAL
.
Синтаксис:
local label_name
Директива должна применяться внутри тела макроса. Все метки label_name внутри макроса становятся локальными. Так что, если макрос используется дважды никаких проблем не появляется:
macro pushstr string
{
local behind
call behind
db string,0
behind:
}
pushstr 'aaaaa'
pushstr 'bbbbbbbb'
call something
На самом деле, behind заменяется на behind?XXXXXXXX
, где XXXXXXXX
— какой-то шестнадцатеричный номер генерируемый препроцессором. Последний пример может быть преобразован к чему-то вроде:
call behind?00000001
db 'aaaaa', 0
behind?00000001:
call behind?00000002
db 'bbbbbbbb', 0
behind?00000002:
call something
Заметьте, Вы не сможете напрямую обратиться к метке содержащей ?
так как это специальный символ в FASM, поэтому он и используется в локальных метках. К примеру, aa?bb
рассматривается как идентификатор aa
, специальный символ ?
и идентификатор bb
.
Если Вам нужно несколько локальных меток — не проблема, их можно указать в одной директиве LOCAL
, разделив запятыми ,
:
macro pushstr string ; делает то же, что и предыдущий макрос
{
local addr, behind
push addr
jmp behind
addr db string,0
behind:
}
Всегда хорошо бы начинать все локальные метки макросов с двух точек ..
— это значит, что они не будут менять текущую глобальную метку. К примеру:
macro pushstr string
{
local behind
call behind
db string, 0
behind:
}
MyProc:
pushstr 'aaaa'
.a:
будет преобразовано в:
MyProc:
call behind?00000001
db 'aaaa', 0
behind?00000001:
.a:
в результате получим метку behind?00000001.a
вместо MyProc.a
. Но если в примере выше behind
заменить на ..behind
, текущая глобальная метка не изменится и будет определена метка MyProc.a
:
macro pushstr string
{
local ..behind
call ..behind
db string,0
..behind:
}
MyProc:
pushstr 'aaaa'
.a:
5.4. Оператор объединения #
У макроязыка FASMа есть ещё одна возможность — манипуляции с идентификаторами. Делается это оператором #
, который объединяет два идентификатора в один. К примеру, a#b
становится ab
, а aaa bbb#ccc ddd
— aaa bbbccc ddd
.
Оператор #
может быть использован только внутри тел макросов, а объединение символов происходит после замены аргументов макроса параметрами. Так что его можно использовать для создания новых идентификаторов из переданных в макрос параметров:
macro string name, data
{
local ..start
..start:
name db data,0
sizeof.#name = $ —..start
}
string s1,'нудные макросы'
string s2,<'а вот и я',13,10,'заставлю тебя их видеть во сне'>
получим:
..start?00000001:
s1 db 'нудные макросы',0
sizeof.s1 = $ —..start?00000001
..start?00000002:
s2 db 'а вот и я',13,10,'заставлю тебя их видеть во сне',0
sizeof.s2 = $ —..start?00000002
так что для всех строк, создаваемых этим макросом будет определён идентификатор sizeof.имя строки
, равный количеству байт строки.
Оператор #
способен так же объединять символьные строки:
macro debug name
{
db 'name: '#b,0
}
debug '1'
debug 'foobar'
будет:
db 'name: 1',0
db 'name: foobar',0
Это полезно при передаче аргументов из макроса в макрос:
macro pushstring string
{
local ..behind
call ..behind
db string,0
..behind:}
macro debug string
{
push MB_OK
push 0 ;empty caption
pushstring 'debug: '#string ;принимает один аргумент
push 0 ;нет окна-предка
call [MessageBox]
}