2014-11-17 4 views
3

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

ответ

2

В 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); 
0

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

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

Спасибо за этот ответ! Я не уверен, что полностью понимаю, но посмотрю на руководство по функциям закрытия и посмотрю, смогу ли я это понять. – 1k5