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:

<p>5.4. Оператор объединения #</p>

У макроязыка FASMа есть ещё одна возможность — манипуляции с идентификаторами. Делается это оператором #, который объединяет два идентификатора в один. К примеру, a#b становится ab, а aaa bbb#ccc dddaaa 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]

}

Перейти на страницу:

Похожие книги