О передаче строк в функции и потоки.
SB - Article
Для начала несколько слов о том, как в скриптах хранятся строки. Для сохранения строки используется два вида переменных: одни для коротких строк ('...'), другой - для длинных ("..."). Переменные первого типа обозначаются символом s рядом с названием (1@s, s$str). Переменные второго - символом v (2@v, v$str1).
Теперь о том, как хранятся сами символы строк. В других языках программирования, чаще всего, переменная типа string не хранит в себе весь набор букв. Такая переменная хранит в себе адрес памяти, где эти буквы располагаются. Стринговая переменная представляет собой по сути указатель на первый символ строки, и занимает, как и любой указатель, 4 байта. Не важно какой длины строка - 1 буква или 500, стринговая переменная всегда в длину 4 байта (в большинстве случаев).
В SA строки хранятся в самих переменных. Как известно, существует 2 вида переменных - локальные и глобальные. Для каждого из них в памяти зарезервировано определенная область памяти ограниченного размера. Например, для каждого потока выделятся 32 переменные по 4 байта и, соответственно, буфер памяти для хранения значений этих переменных в 128 байтов. Аналогичная ситуация с буфером глобальных переменных (его размер может меняться в разных майнах при компиляции).
Строки хранятся внутри данного буфера переменных. Это означает, что в стринговую переменную 0@s записывается не указатель на первую букву слова MAIN, а сами эти буквы (в ASCII-кодах).
Вернемся теперь к двум видам строк - коротким и длинным (строкам с переменной длиной).
Короткие строки всегда занимают в памяти 8 байтов. В такую переменную можно записать до 7 символов включительно, остаток заполняется нулями. Не важно, 1 буква в строке или 7, размер такой строки всегда 8 байтов. Таким образом, если вы записываете в переменную 1@s строку 'STRING' она займет 8 байтов. Учитывая, что буквы строк хранятся в самих переменных (см. выше), а одна переменная может хранить только 4 байта (1 буква - 1 байт), то часть строки будет записана в следующую по порядку переменную: 2@.
Получается: 1@ хранит 'STRI', 2@ хранит 'NG'.
С длинными строками ситуация аналогичная, с единственной разницей, что они занимают 4 переменные (16 байтов).
1@v = "LONG_STRING" => 1@ = "LONG", 2@ = "_STR", 3@ "ING", 4@ - хранит остаток (нулевые байты).
Обратите внимание, 1@v = "MAIN" хоть и хранит только 4 символа, но запись такой переменной затрет значения не только 1@ но и 2@, 3@ и 4@
16 байтов является пределом для стринговых переменных. Нельзя записать в переменную 1@v строку длиной 20 символов, например.
Если подытожить, строки занимают в памяти либо 8 либо 16 байтов (зависит от типа строки). Для их хранения требуется 2 или 4 переменные, идущие подряд (0@, 1@; $1, $2 и т п.).
Теперь перейдем к главному. В новые потоки, создаваемые опкодом 004F, можно передавать числовые параметры, значения которых записываются по порядку в локальные переменные нового потока.
- Code:
create_thread @new 100 $ONMISSION 1@
в потоке @new переменная 0@ будет равна 100, 1@ равно значению $ONMISSION, 2@ равно значению 1@ потока, из которого был вызван опкод 004F.
Те же правила действуют при вызове SCM-функций:
- Code:
0AB1: call_scm_func @Recalc 1 -1.0
в функции Recalc переменная 0@ будет равна -1.0.
Но стандартными способами передать не число, а строку в поток/функцию нельзя.
- Code:
0AB1: call_scm_func @endT 1 'BENZIN' // так нельзя
Однако есть другой способ. Вспомним, что строка хранится в переменных. Строка - это набор букв, которые по сути являются числами. Мы можем сохранить строку в стринговую переменную и передать ее по частям:
- Code:
0@s = 'BENZIN'
0AB1: call_scm_func @endT 2 0@ 1@ // передаем обе части короткой строки
а в функции используем строку также через стринговую переменную:
- Code:
:endT
0459: end_thread_named 0@s // 'BENZIN'
0AB2: ret 0
Для длинных строк правило аналогичное, но требуется передать значения 4-х переменных:
- Code:
0@v = "SNEAKERBINCBLK" // 0@..3@
4@v = "SNEAKER" // 4@..7@
8@ = 3
0AB1: call_scm_func @clothes 9 0@ 1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ // передаем две строки и числовой параметр
- Code:
:clothes
087B: set_player $PLAYER_CHAR clothes_texture 0@v model 4@v body_part 8@
0AB2: ret 0
Возможно, для полного понимания данного текста вам потребуется немного воображения. Важно понять принципы хранения строк в памяти и все станет ясно.