如何从c函数回调lua函数

时间:2010-04-22 03:25:52

标签: lua callback

我有一个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 "

编辑:

This link提供了一种存储回调函数供以后使用的方法。

//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

2 个答案:

答案 0 :(得分:9)

我不确定我理解你的问题,如果你问的是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函数。

(编辑:根据Nick的建议将lua_call更改为lua_pcall。为了简洁,我仍然省略了任何错误处理。

答案 1 :(得分:3)

使用不同签名调用不同Lua函数的便捷方式:

一个。创建一个能够安全维护Lua状态的类,并提供简单的界面。不要一次又一次地从头开始调用Lua函数(通过大量的push / pop工作和断言) - 只需使用这个类接口。这是一种安全,快捷,方便的方法。

B中。定义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);
}

d。设置错误处理程序(如果错误,lua_pcall将调用此Lua函数)

void setErrorHandler(const char * funcName)
{
  lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName);
  this->err_h = lua_gettop(lua_state);
}