嵌套的lua_CFunction调用

如何处理嵌套的lua_CFunction调用是最好的方式?假设我有两个像这样的函数:

   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()提供其自己的调用堆栈,因此没有必要修改它。但是,对于有更多参数的函数,此解决方案似乎过于复杂,因为它需要在堆栈上复制所有参数。

简而言之:从另一个函数中调用lua_CFunction的推荐方式/好方法是什么?

点赞
用户2723873
用户2723873

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);
2014-11-17 23:03:11
用户258523
用户258523

我认为通过 Lua 调用它是推荐的方式,但如果由于某种原因你不想这样做,那么 Timma 的建议是正确的。

2014-11-18 00:33:39
用户2328287
用户2328287

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) --[[function2的函数体]] end)(arg)
end

因此,每次都创建新的函数并调用它。

对于 C 函数来说,这很不错,因为无需编译,也不需要上值。

此外,Lua 5.2 引入了轻量级函数。

但如果你想要等价于以下 Lua 代码的函数:

local 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) {

  ...

  -- 将 `function2` 推入堆栈
  lua_rawgeti(L, LUA_REGISTRYINDEX, f2_ref);

  -- 如上
}

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){
  -- 在这里,我们创建了 Lua 函数(闭包)的实例
  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-18 14:04:09