Вложенные вызовы lua_CFunction

Каков наилучший способ справиться с вложенными вызовами 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 ответа

В function1 вы ожидаете, что в нижней части стека находятся пользовательские данные. Когда вы звоните function2 напрямую LuaState не изменился, и поэтому в нижней части все еще находятся пользовательские данные.

Вы можете успешно позвонить function2 от function1 гарантируя, что целое число находится в индексе 1.

Вы можете сделать это, позвонив lua_insert(L, 1) который переместит вершину (предполагая индекс 2), в индекс 1.

Вы также можете сделать это, вытолкнув все значения, вернув целое число обратно:

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

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

Я бы сказал, что звонить через lua - рекомендуемый способ сделать это, но если вы не хотите делать это по какой-то причине, то предложения Тиммы - правильные.

Другие вопросы по тегам