О переносе и вызове функции C - PullRequest
5 голосов
/ 28 февраля 2011

Я получил этот вопрос из этого китайского блога http://chenyufei.info/blog/2011-02-28/wrap-c-function-closure-gcc-nested-function/ Автор хочет использовать замыкание на языке c, и он обнаружил, что GCC обладает способностью вложенной функции (и замыкания).Например:

typedef int (*func_t)(int arg);


int foo(int a) {

    return a + 1;

}


func_t create_wrap_function(func_t f) {

    int wrapped(int arg) {

        // call original function

        int val = f(arg);

        fprintf(log_func_call, "arg: %d ret: %d", arg, val);

        return val;
    }

    return wrapped;
}

Но это не распространенное решение.Функция create_wrap_function имеет фиксированный формат функции, поскольку func_t ограничивает формат.

Как мы знаем, Lua имеет замыкание и может также вызывать функцию C.То, что я хочу реализовать следующим образом: функции, которые мы хотим вызвать, это foo1 и foo2, они имеют разные типы аргументов и возвращаемое значение.

int foo1(int a) {
    ...
    return intValue;
}

double foo2(char* str, double a) {
   ...
   return dblValue;
}

В клиенте C вызовите функцию следующим образом:

lua_returnValue returnValue1 = Do_Lua_Wrap(__FILE__, __LINE__, foo1, 1);
lua_returnValue returnValue2 = Do_Lua_Wrap(__FILE__, __LINE__, foo2, "string data", 1.2345);

В Do_Lua_Wrap он передает foo1 и 1 в функцию Lua, а затем вызывает функцию foo1 как обычный процесс.Затем передайте функцию foo2 и один символ char * и одно двойное значение в функцию Lua, затем вызовите функцию foo2, как обычный процесс.В функции Lua она может регистрировать информацию о FILE и LINE и записывать дополнительный журнал об аргументах функции.

Но я понятия не имею, какнаписать функцию Do_Lua_Wrap на C и Lua, это возможно?

Если возможно, не могли бы вы дать мне несколько советов?

1 Ответ

2 голосов
/ 01 марта 2011

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

  1. Первым было бы включить строку формата в виде семейства printf или двоичных форматов упаковки, часто используемых в языках более высокого уровня,Например, взгляните на шаблон формата, используемый в модуле lpack Lua.Ключ заключается в том, чтобы просмотреть строку формата, чтобы определить, сколько и какие аргументы предоставляются.

  2. В качестве альтернативы вы можете реализовать вариант вариант .Каждый аргумент должен быть заключен в такую ​​структуру.Кроме того, в качестве первого параметра необходимо указать общее количество аргументов.

  3. Наконец, вы можете передавать аргументы в двух массивах вместо использования функции с переменными числами.Первый массив будет содержать перечисляемые типы, соответствующие цели void * указателей во втором массиве.Этот метод требует большей части домашнего кода для клиентского кода, но он довольно чистый.Также потребуется аргумент, указывающий длину массивов, или значение часового в конце одного или обоих массивов.

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

...