Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.

Реклама



**Как получить V.I.P** (Перейти)
Чтобы заказать рекламу на Pro-Pawn.Ru, обращайтесь в Skype.
Баннерная реклама 100руб/мес, Текстовая 50руб/мес.
Показано с 1 по 6 из 6
  1. #1
    Аватар для Daniel_Cortez
    new fuck_logic[0] = EOS;

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    1,419
    Репутация:
    1998 ±

    Лайфхак с функциями для Pawn AMX

    Привет всем.

    Не так давно в одном из своих личных проектов мне понадобилось сделать нативные функции для Pawn AMX.
    Для примера возьмём одну из таких функций: она должна была принимать 2 аргумента (ID участка памяти, в котором нужно отсортировать значения, как в массиве, и порядок сортировки) и нужно было сделать проверку на то, что этих аргументов передано нужное количество (кто знает, может быть в скрипте неправильный заголовок функции с 1 или даже 0 параметрами вместо 2?)
    Выглядел код примерно так:
    PHP код:
    static cell AMX_NATIVE_CALL n_MemSort(AMX *amx, const cell *params)
    {
        
    // CheckArgsNumber проверяет кол-во аргументов и, если их меньше, чем нужно, поднимает ошибку.
        
    if (!CheckArgsNumber(amxparams2))
            return 
    0;
        
    // Если есть нужное кол-во аргументов - отсортировать значения в участке памяти.
        
    return MemoryPool_Sort(amxparams[1], params[2]);

    Меня этот результат не устроил сразу по нескольким причинам.
    Во-первых, чтобы понять, что кроется в 1-м и 2-м аргументе, нужно открывать заголовочный файл на Pawn (*.inc).
    Во-вторых, чем больше таких аргументов в функции, тем легче их перепутать.
    В-третьих, последний параметр в CheckArgsNumber нужно подсчитывать вручную. ИЧСХ, с ним тоже легко ошибиться (например, указать 3 вместо 2), особенно из-за copy-paste.

    Мне захотелось переложить работу по контролю аргументов функции на компилятор, поэтому я придумал небольшой трюк с перечислением ID аргументов в enum:
    PHP код:
    static cell AMX_NATIVE_CALL n_MemSort(AMX *amx, const cell *params)
    {
        
    enum
        
    {
            
    args_size,
            
    arg_pointer_id,
            
    arg_sort_type,
            
    __dummy_elem_args_expected_number __dummy_elem_ 1
        
    };
        if (!
    CheckArgsNumber(amxparamsargs_expected_number))
            return 
    0;
        return 
    MemoryPool_Sort(amxparams[arg_pointer_id], params[arg_sort_type]);

    С таким вариантом у каждого из параметров есть своё название, перепутать params[arg_pointer_id] и params[arg_sort_type] куда сложнее, чем params[1] и params[2], а в CheckArgsNumber не нужно самостоятельно считать количество параметров функции - оно само подсчитывается в args_expected_number.

    P.S. Если кому-нибудь будет интересно, вот сама функция CheckArgsNumber:
    PHP код:
    inline bool CheckArgsNumber(AMX *amx, const cell *paramscell num_expected)
    {
        if (
    params[0] / (cell)sizeof(cell) < num_expected)
        {
            
    amx_RaiseError(amxAMX_ERR_PARAMS);
            return 
    false;
        }
        return 
    true;


    Автор: Daniel_Cortez

    Специально для Pro-Pawn.ru
    Копирование данной статьи на других ресурсах без разрешения автора запрещено!

  2. #2
    Аватар для ziggi
    Проверенный

    Статус
    Оффлайн
    Регистрация
    14.05.2015
    Сообщений
    639
    Репутация:
    511 ±
    Годно, надо попробовать. Для полноты картины не помешало бы выложить функцию CheckArgsNumber (понятно, что функция проста, но всё же).

  3. #3
    Аватар для Daniel_Cortez
    new fuck_logic[0] = EOS;

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    1,419
    Репутация:
    1998 ±
    Не то, чтобы много откликов, но и отрицательных отзывов тоже нет, поэтому, полагаю, можно переместить это в подраздел "Разработки".
    Заодно добавил функцию CheckArgsNumber, она очень простая на самом деле.

  4. #4
    Аватар для VVWVV
    Пользователь

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    358
    Репутация:
    171 ±
    Отличный трюк. Самое главное, что мне понравилось - читаемость кода. Теперь не придётся писать какие-то занудные комментарии.

  5. #5
    Аватар для ziggi
    Проверенный

    Статус
    Оффлайн
    Регистрация
    14.05.2015
    Сообщений
    639
    Репутация:
    511 ±
    Есть ли возможность узнать имя функции в CheckArgsNumber как-то через AMX?
    Я пока придумал только это:
    PHP код:
    inline bool CheckArgsNumber(AMX *amx, const char *func, const cell *paramscell num_expected)
    {
        if (
    params[0] / (cell)sizeof(cell) < num_expected) {
            
    logprintf(" * " PLUGIN_NAME ": Incorrect parameter count for \"%s\", %d != %d\n"funcparams[0] / 4num_expected);
            
    amx_RaiseError(amxAMX_ERR_PARAMS);
            return 
    false;
        }
        return 
    true;

    PHP код:
    if (!CheckArgsNumber(amx__func__paramsargs_expected_number)) {
        return 
    0;

    UPD.
    Хотя лучше, наверное, применять конструкцию вида:
    PHP код:
    inline bool CheckArgsNumber(AMX *amx, const cell *paramscell num_expected)
    {
        if (
    params[0] / (cell)sizeof(cell) < num_expected) {
            
    amx_RaiseError(amxAMX_ERR_PARAMS);
            return 
    false;
        }
        return 
    true;
    }
    #define PRINT_PARAM_ERROR() \
        
    logprintf(" * " PLUGIN_NAME ": Incorrect parameter count for \"%s\", %d != %d\n"__func__params[args_size] / 4args_expected_number
    PHP код:
    if (!CheckArgsNumber(amxparamsargs_expected_number)) {
        
    PRINT_PARAM_ERROR();
        return 
    0;

    Последний раз редактировалось ziggi; 19.11.2016 в 11:31.

  6. #6
    Аватар для Daniel_Cortez
    new fuck_logic[0] = EOS;

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    1,419
    Репутация:
    1998 ±
    По идее это хост-приложение должно выводить информацию об ошибках времени выполнения в интерпретаторе. Так что, ИМХО, настоящий вопрос здесь - "почему сервер SA:MP этого не делает, оставляя все ошибки скрытыми?"
    К слову, достаточно добавить всего лишь пару-тройку строк кода, чтобы, как минимум, отобразить суть ошибки (например, "stack/heap collision" или "array index out of bounds"), но в SA:MP даже этого нет (и не будет, по очевидным причинам).

    Если же говорить о том, как узнать имя текущей нативной функции, в этом может помочь регистр CIP (amx->cip).
    Чуть позже (сегодня) я выложу код, но в отдельной теме, заодно постараюсь объяснить всю теорию.

    UPD: http://pro-pawn.ru/showthread.php?14522

 

 

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •