【问题标题】:Nested lua_CFunction calls嵌套的 lua_CFunction 调用
【发布时间】:2015-01-14 23:14:24
【问题描述】:

处理嵌套的 lua_CFunction 调用的最佳方法是什么?假设我有两个这样的功能:

static int function2(lua_State *L) {
   int i = luaL_checkint(L, 1);

   /* do something */

   return 1;
};

static int function1(lua_State *L) {
   struct udata *u = luaL_checkudata(L, 1, UDATA_METATABLE);
   int i = luaL_checkint(L, 2);

   /* do something */

   /* this does not work, first on call stack is udata, not int */
   return function2(L);
};

上面的函数调用不起作用。一种选择是修改function2() 以使用堆栈上的最后一个元素(索引-1),但这通常不是一个解决方案,因为function2() 可能会从具有不同调用堆栈的不同位置调用。 另一种方法是将return function2(L); 替换为

lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, 1);  /* need to know number of results */

我假设这为function2() 提供了自己的调用堆栈,因此无需修改它。但是这种解决方案对于具有更多参数的函数来说似乎过于复杂,因为它需要将所有参数都复制到堆栈中。

tl;dr:从另一个内部调用lua_CFunction 的推荐方法/好方法是什么?

【问题讨论】:

    标签: c lua lua-api


    【解决方案1】:

    function1 中,您期望堆栈的底部是用户数据。 当你直接调用function2 时,LuaState 并没有改变,因此底部仍然是用户数据。

    您可以通过确保整数在索引 1 处成功地从 function1 调用 function2

    您可以通过调用 lua_insert(L, 1) 来做到这一点,这会将顶部(假设索引 2)移动到索引 1。

    您也可以通过弹出所有值并重新推入整数来做到这一点:

    lua_pop(L, lua_gettop(L));
    lua_pushnumber(L, i);
    return function2(L);
    

    【讨论】:

      【解决方案2】:

      lua_CFunction 不是完整的 Lua 函数。它只是一种创建 Lua 函数/闭包的方法。

      static int function1(lua_State *L) {
          ....
          int top = lua_gettop(L);
          lua_pushcfunction(L, function2);
          lua_pushvalue(L, 2);
          lua_call(L, 1, LUA_MULTRET);
          return lua_gettop(L) - 1;
      }
      

      Lua 等价物是

      function function1(arg)
        return (function(arg) --[[body of f2]] end)(arg)
      end
      

      所以你每次都创建新函数并调用它。 对于 C 函数,它是完全可以的,因为它不需要编译,你也不需要 upvalue。 Lua 5.2 也为此引入了 light 函数。 但是如果你想要等价于

      int i = 1
      local function function2(arg)
        i = i + 1
        ...
      end
      
      function function1(arg)
        return function2(arg)
      end
      

      你需要一种方法来找到真正的 Lua 函数,例如(未测试)

      int f2_ref;
      
      static int function1(lua_State *L) {
      
        ...
      
        -- push `function2` on stack
        lua_rawgeti(L, LUA_REGISTRYINDEX, f2_ref);
      
        -- as above
      }
      
      static int function2(lua_State *L) {
        int my_upvalue = lua_tonumber(L, lua_upvalueindex(1));
        my_upvalue++;
        lua_pushnumber(L, my_upvalue);
        lua_replace(L, lua_upvalueindex(1));
      
      
        ...
      }
      
      int luaopen_foo(lua_State *L){
        -- Here we create instance of Lua function(closure)
        lua_pushnumber(L, 1);
        lua_pushcclosure(L, function2, 1);
        f2_ref = luaL_ref(L, LUA_REGISTRYINDEX);
      
        lua_pushcclosure(L, function1, 0);
        return 1;
      }
      

      【讨论】:

      • 感谢您的回答!我不确定我是否完全理解,但会看一下闭包函数的手册,看看我是否能弄明白。
      【解决方案3】:

      我会说通过 lua 调用它推荐的方法,但如果您出于某种原因不想这样做,那么 Timma 的建议是正确的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-25
        • 2017-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-12
        • 2016-02-24
        • 1970-01-01
        相关资源
        最近更新 更多