PDA

Просмотр полной версии : [Вопрос] Ошибка с SendMes



vovandolg
17.05.2016, 19:10
[17:48:42] [debug] Server crashed while executing beta45.amx
[17:48:42] [debug] AMX backtrace:
[17:48:42] [debug] #0 native format () from samp03svr
[17:48:42] [debug] #1 002387f8 in SendMes (playerid=1, color=-1347440726, fstring[]=@005a5ec8 "%s - %s[%d]", ... <3 arguments>) at D:\Program\Арбайтен\beta45.pwn:38401
[17:48:42] [debug] #2 00132b00 in public OnPlayerCommandText (playerid=1, cmdtext[]=@0061f654 "/leaders") at D:\Program\Арбайтен\beta45.pwn:23480

В гугле почти пусто насчёт этой темы)


stock SendMes(playerid, color, fstring[], {Float, _}:...)
{
static const STATIC_ARGS = 3;
new n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL;
if (n)
{
new message[128], arg_start, arg_end;
#emit CONST.alt fstring
#emit LCTRL 5
#emit ADD
#emit STOR.S.pri arg_start
#emit LOAD.S.alt n
#emit ADD
#emit STOR.S.pri arg_end
do
{
#emit LOAD.I
#emit PUSH.pri
arg_end -= BYTES_PER_CELL;
#emit LOAD.S.pri arg_end
}
while (arg_end > arg_start);
#emit PUSH.S fstring
#emit PUSH.C 128
#emit PUSH.ADR message

n += BYTES_PER_CELL * 3;
#emit PUSH.S n
#emit SYSREQ.C format

n += BYTES_PER_CELL;
#emit LCTRL 4
#emit LOAD.S.alt n
#emit ADD
#emit SCTRL 4
return SCM(playerid, color, message);
}
else return SCM(playerid, color, fstring);
}

ziggi
17.05.2016, 19:19
1. Почему размер message 128?
2. Покажи как вызываешь SendMes.
3. Покажи строки 23480 и 38401.

VVWVV
17.05.2016, 19:22
Сколько раз говорилось: "Не используйте SendMes". К тому же, данная функция - неправильна, т.к. неправильно задан размер массива.
Вроде бы, с использованием простых Format и SendMes будет быстрее. К тому же, вы могли бы использовать функции strcat, которые намного быстрее, чем format.

vovandolg
17.05.2016, 19:29
1. Почему размер message 128?
2. Покажи как вызываешь SendMes.
3. Покажи строки 23480 и 38401.

1. hz)) сделал 145
2. Ниже это и есть строка 23480
3.___________
23480| SendMes(playerid,COLOR_GREY,"%s - %s[%d]",ttext,pInfo[i][pName],i);

38401|

#emit SYSREQ.C format
n += BYTES_PER_CELL;
#emit LCTRL 4

vovandolg
18.05.2016, 00:41
К тому же, вы могли бы использовать функции strcat, которые намного быстрее, чем format.

Если я не ошибаюсь strcat для слепки многих строк и быстрее только когда много слепок надо, а у меня одна строка для форматирования..

Я что залип на этой функции, смотрю написана на emit и прочих причудах павна,
а на форуме об таких кодах говорят что это божественные коды, вот и залип в этой функции,
ошибка всё равно осталась с правильным рассчётом..

В общем я так понимаю надо переходить на обычный SCM и форматирование(уфф сколько в моде придётся копаться)

vovandolg
18.05.2016, 16:19
Как мне перенести пачку аргументов с переменными в таком случае:
(не сталкивался с таким и не знаю как правильно спросить)

stock SendMes(playerid, color, fstring[], {Float, _}:...)
{
new skr[145];
format(skr, 145, fstring, {Float, _}:...);
SendClientMessage(playerid, color, skr);
}

TheMallard
18.05.2016, 16:59
Такое не прокатит. Советую посмотреть на y_va. Однако намного лучше форматировать стандартными средствами.

L0ndl3m
18.05.2016, 18:40
Как мне перенести пачку аргументов с переменными в таком случае:
(не сталкивался с таким и не знаю как правильно спросить)

stock SendMes(playerid, color, fstring[], {Float, _}:...)
{
new skr[145];
format(skr, 145, fstring, {Float, _}:...);
SendClientMessage(playerid, color, skr);
}
В таком случае вам помогут функции getarg и numargs. Но не советую вам в будущем использовать эту функцию: при вызове данной функции вы будете постоянно использовать большое количество ненужных ячеек.

vovandolg
18.05.2016, 18:57
Так и подумал что будет много излишки если так юзать, переведусь на обычное формат-ие:smoke:
Можно закрывать темку...

Found
18.05.2016, 19:09
Как мне перенести пачку аргументов с переменными в таком случае:
(не сталкивался с таким и не знаю как правильно спросить)

stock SendMes(playerid, color, fstring[], {Float, _}:...)
{
new skr[145];
format(skr, 145, fstring, {Float, _}:...);
SendClientMessage(playerid, color, skr);
}

Данную функцию можно использовать в сумме с глобальной переменной.
Например:
Мы объявим глобальную переменную:


new
global_string[ 256 ];

После этого, мы добавляем в тело функции, данный участок кода. (Иными словами, мы очищаем глобальную переменную)

global_string[0] = EOS;

Далее, нам необходимо будет статичные аргументы отделить от динамичных и пустить цикл, с которыми в свою очередь будут работать функции - getarg(...).

Таким образом, глобальная переменная, будет автоматически очищаться при инициализации функции.
Ну, а идеальный вариант, это конечно же использование директивы #define.

#define prepare(%0,%1,%2,%3) global_string[0] = EOS; format(global_string, sizeof global_string, %2, %3); SendClientMessage(%0, %1, %2)

Но опять же и здесь нас ожидают подводные камни.
Например, будет проблема для тех, кто привык писать функции подобным образом:


prepare( playerid, C_WHITE, "Playerid: %d",
playerid
);

VVWVV
18.05.2016, 19:24
Данную функцию можно использовать в сумме с глобальной переменной.
Например:
Мы объявим глобальную переменную:


new
global_string[ 256 ];

После этого, мы добавляем в тело функции, данный участок кода. (Иными словами, мы очищаем глобальную переменную)

global_string[0] = EOS;

Далее, нам необходимо будет статичные аргументы отделить от динамичных и пустить цикл, с которыми в свою очередь будут работать функции - getarg(...).


Нет смысла использовать такой подход, ибо если вы не будете использовать global_string, то переменная всё равно будет инициализирована в сегмент данных. И ещё, вы всегда можете оптимизировать способ с обычными функциями - есть тема на форуме от DC. Кстати, может возникнуть ряд других проблем.



Таким образом, глобальная переменная, будет автоматически очищаться при инициализации функции.
Ну, а идеальный вариант, это конечно же использование директивы #define.

#define prepare(%0,%1,%2,%3) global_string[0] = EOS; format(global_string, sizeof global_string, %2, %3); SendClientMessage(%0, %1, %2)

Но опять же и здесь нас ожидают подводные камни.
Например, будет проблема для тех, кто привык писать функции подобным образом:


prepare( playerid, C_WHITE, "Playerid: %d",
playerid
);


К тому же, массив не отчищается. Символ нуля указывает на окончание строки.



Таким образом, глобальная переменная, будет автоматически очищаться при инициализации функции.

Точнее сказать: "вызов функции".

Found
18.05.2016, 19:31
Нет смысла использовать такой подход, ибо если вы не будете использовать global_string, то переменная всё равно будет инициализирована в сегмент данных. И ещё, вы всегда можете оптимизировать способ с обычными функциями - есть тема на форуме от DC. Кстати, может возникнуть ряд других проблем.



К тому же, массив не отчищается. Символ нуля указывает на окончание строки.


Функция SendMes в данном случае будет быстрее, чем ваш способ, ибо вы всегда будете вызывать один и тот же код несколько раз.

Конечно же она будет инициализирована. На самом деле суть этой переменной в том, чтобы форматировать и подготавливать выражения.

Можно ссылочку?

Да, перепутал. Правильнее будет:
global_string[0] = 0;

Поэтому я предложил вариант с #define.

L0ndl3m
18.05.2016, 19:33
new
global_string[ 256 ];

После этого, мы добавляем в тело функции, данный участок кода. (Иными словами, мы очищаем глобальную переменную)

global_string[0] = EOS;
Нельзя сказать, что это очищение массива. "Очищается" только первый элемент массива (в данном случае это global_string[0]). Конструктор кода устроен таким образом, что он будет "сканировать" строку до того времени, пока не найдёт нулевой символ. Остальной текст (начиная с первого индекса (global_string[1])) будет сохранён в памяти.

Found
18.05.2016, 19:38
Нельзя сказать, что это очищение массива. "Очищается" только первый элемент массива (в данном случае это global_string[0]). Конструктор кода устроен таким образом, что он будет "сканировать" строку до того времени, пока не найдёт нулевой символ. Остальной текст (начиная с первого индекса (global_string[1])) будет сохранён в памяти.

Да, не спорю, ошибся. Выше уже исправил, если мне не изменяет память, то именно таким образом происходит очистка переменной.

L0ndl3m
18.05.2016, 19:45
Да, не спорю, ошибся. Выше уже исправил, если мне не изменяет память, то именно таким образом происходит очистка переменной.
Для понимания машины этого достаточно, но человек должен понимать, что он не освобождает весь массив от данных.

vovandolg
19.05.2016, 00:46
Для тех кто был в танке и пытался что то мне подсунуть,
я хотел гмошный SendMes перештопать в свой чтобы не лазеть не заменять все мессы,
но тут ведь проблема вышла, аргумент с переменными может быть и не один и не три а по разному.

Daniel_Cortez
20.05.2016, 15:26
Функция SendMes (именно с передачей переменного числа параметров через #emit) действительно опасна в использовании под Linux.
Я не проверя работу именно этой функции на версии сервера SA-MP для Linux, но ещё в прошлом году решил провести эксперимент: откомпилировал интерпретатор Pawn 3.2 под линью и скормил ему .amx с коллбэком, который передавал переменное количество параметров нативной функции; принцип передачи параметров был такой же, как и в SendMes. После каждой попытки вызова того коллбэка интерпретатор падал (segmentation fault). Откомпилировал интерпретатор под вендой и скормил ему тот же скрипт - всё работало. Ещё раз скомпилировал его в режиме отладки и дебажил в Visual Studio - никаких признаков неправильной работы. Видимо, это как-то было связано с особенностями реализации интерпретатора в его оптимизированной версии для GCC, которая использовалась под линуксом.


Для тех кто был в танке и пытался что то мне подсунуть,
я хотел гмошный SendMes перештопать в свой чтобы не лазеть не заменять все мессы,
но тут ведь проблема вышла, аргумент с переменными может быть и не один и не три а по разному.
Вы это так говорите, как будто другие виноваты в том, что вы любите грызть кактус и в упор отказываетесь принимать нормальное решение.