【问题标题】:how to callback a lua function from a c function如何从c函数回调lua函数
【发布时间】:2010-04-23 16:48:38
【问题描述】:

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

【问题讨论】:

    标签: lua callback


    【解决方案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 函数。

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

    【讨论】:

    • 最好使用 lua_pcall,它将错误推送到堆栈而不是崩溃。
    • 很好的正确例子。但在实践中,最好使用通用的、经过良好测试的接口,尽管一次又一次地编写这样的 lua_test_callback() 函数。
    【解决方案2】:

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

    A.创建一个可以安全维护 Lua 状态并提供简单接口的类。不要一次又一次地从头开始编写对 Lua 函数的调用(有大量的 push/pop 工作和断言)——只需使用这个类接口。这是一种安全、快速、方便的方法。

    B.定义 push 和 pop 方法以在 Lua 堆栈上/从 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);
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-14
      • 2014-09-01
      • 2010-11-15
      • 2018-04-23
      • 2018-09-16
      • 2013-02-19
      • 2015-12-30
      • 2022-01-04
      相关资源
      最近更新 更多