Как вызвать функцию lua из функции c
У меня есть функция C (A) test_callback
, принимающая указатель на функцию (B) в качестве параметра, а A будет "обратный вызов" B.
//typedef int(*data_callback_t)(int i);
int test_callback(data_callback_t f)
{
f(3);
}
int datacallback(int a )
{
printf("called back %d\n",a);
return 0;
}
//example
test_callback(datacallback); // print : called back 3
Теперь я хочу обернуть test_callback
, чтобы их можно было вызвать из lua, предположим, что имя lua_test_callback
, а также входной параметр для него будет функцией lua. Как я должен достичь этой цели?
function lua_datacallback (a )
print "hey , this is callback in lua" ..a
end
lua_test_callback(lua_datacallback) //expect to get "hey this is callback in lua 3 "
ИЗМЕНИТЬ:
Эта ссылка предоставляет способ хранения функции обратного вызова для последующего использования.
//save function for later use
callback_function = luaL_ref(L,LUA_REGISTRYINDEX);
//retrive function and call it
lua_rawgeti(L,LUA_REGISTRYINDEX,callback_function);
//push the parameters and call it
lua_pushnumber(L, 5); // push first argument to the function
lua_pcall(L, 1, 0, 0); // call a function with one argument and no return values
Ответы
Ответ 1
Я не уверен, что я понимаю ваш вопрос, если вы спрашиваете, что будет выглядеть lua_test_callback
на C, это должно быть что-то вроде этого
int lua_test_callback(lua_State* lua)
{
if (lua_gettop(lua) == 1 && // make sure exactly one argument is passed
lua_isfunction(lua, -1)) // and that argument (which is on top of the stack) is a function
{
lua_pushnumber(lua, 3); // push first argument to the function
lua_pcall(lua, 1, 0, 0); // call a function with one argument and no return values
}
return 0; // no values are returned from this function
}
Вы не можете просто обернуть test_callback
, вам нужно совсем другое выполнение для вызова функций Lua.
(изменить: изменил lua_call
на lua_pcall
, как было предложено Ником. Я по-прежнему опускал любую обработку ошибок для краткости)
Ответ 2
Удобный способ совершения вызовов к различным функциям Lua с различными сигнатурами:
а. Создайте класс, который будет поддерживать состояние Lua безопасно и обеспечит легкий интерфейс. Не переписывайте вызовы функций Lua с нуля (с большим количеством push/pop work и утверждает) снова и снова - просто используйте этот интерфейс класса. Это безопасный, быстрый и удобный подход.
В. Определите методы push и pop для ввода/выключения аргументов в/из стека Lua:
template<typename T> void push(T argument);
template<typename T> void get(const int index, T& return_value);
template<> void State::push(bool arg)
{
lua_pushboolean (lua_state, arg ? 1 : 0);
}
template<> void State::push(float arg)
{
lua_pushnumber (lua_state, arg);
}
template<> void State::push(int arg)
{
lua_pushnumber (lua_state, arg);
}
// ...
template<> void State::get(const int index, bool& ret)
{
if (!lua_isboolean(lua_state, index)) { ... }
ret = lua_toboolean(lua_state, index) != 0;
}
С. Определите функции для вызова функций Lua:
// Call function that takes 1 argument and returns nothing
template <typename A1>
void call(const char * funcName, A1 arg1)
{
lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName); // push global function f on stack
push (arg1); // push first argument on stack
assert_call( lua_pcall(lua_state, 1, 0, this->err_h) ); // call function taking 1 argument and getting no return value
}
// call function that takes 2 argument and returns 1 value
template <typename R1, typename A1, typename A2>
void callr1(const char * funcName, R1& res, A1 arg1, A2 arg2)
{
lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName); // push global function f on stack
push (arg1); // push first argument on stack
push (arg2);
assert_call( lua_pcall(lua_state, 2, 1, this->err_h) ); // call function taking 2 arguments and getting 1 return value
get (-1, res);
lua_pop(lua_state, 1);
}
Д. Установите обработчик ошибок (lua_pcall вызовет эту функцию Lua, если ошибка)
void setErrorHandler(const char * funcName)
{
lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName);
this->err_h = lua_gettop(lua_state);
}