嵌套的lua_CFunction调用

时间:2014-11-17 22:08:49

标签: c lua lua-api

处理嵌套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的推荐方式/好方法是什么?

3 个答案:

答案 0 :(得分:3)

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

您可以通过确保整数位于索引1,从function2成功呼叫function1

您可以通过调用lua_insert(L, 1)来执行此操作,该lua_pop(L, lua_gettop(L)); lua_pushnumber(L, i); return function2(L); 会将顶部(假设索引2)移至索引1。

你也可以通过弹出所有值来重新推动整数:

{{1}}

答案 1 :(得分: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也为此引入了光功能。 但是如果你想要等效的

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;
}

答案 2 :(得分:0)

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