问题 如何从c函数回调lua函数


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

3179
2018-04-22 03:25


起源



答案:


如果你问的是什么,我不确定我理解你的问题 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 正如尼克所说。为简洁起见,我仍然省略了任何错误处理)


9
2018-04-22 08:51



最好使用lua_pcall将错误推送到堆栈而不是崩溃。 - Nick Van Brunt
很好的正确例子。但实际上,尽管一次又一次地编写了这样的lua_test_callback()函数,但最好使用通用的,经过良好测试的界面。 - topright gamedev


答案:


如果你问的是什么,我不确定我理解你的问题 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 正如尼克所说。为简洁起见,我仍然省略了任何错误处理)


9
2018-04-22 08:51



最好使用lua_pcall将错误推送到堆栈而不是崩溃。 - Nick Van Brunt
很好的正确例子。但实际上,尽管一次又一次地编写了这样的lua_test_callback()函数,但最好使用通用的,经过良好测试的界面。 - topright gamedev


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

A.创建一个能够安全维护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;
}

C.定义调用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);
}

3
2018-04-22 18:00