3

处理嵌套的 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);by

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

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

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

4

3 回答 3

3

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

您可以通过确保整数位于索引 1 处成功调用function2from 。function1

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

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

lua_pop(L, lua_gettop(L));
lua_pushnumber(L, i);
return function2(L);
于 2014-11-17T23:03:11.800 回答
1

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;
}
于 2014-11-18T14:04:09.820 回答
0

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

于 2014-11-18T00:33:39.867 回答