英文:
Calling lua_pcall clear the lua_State
问题
以下是您要求的代码翻译部分:
这是我正在测试的代码的简化版本:
int f(lua_State *L)
{
std::cout << std::format("- Function call, stack size: {}, parameter value: {}\n", lua_gettop(L), lua_tointeger(L, 1));
return 0;
}
int main()
{
lua_State *const L = luaL_newstate();
luaL_loadstring(L, "f1(1)");
luaL_loadstring(L, "f2(2)");
lua_register(L, "f1", f);
lua_register(L, "f2", f);
std::cout << "\nStack before call:\n";
for (int b = 0, e = lua_gettop(L); b != e; ++b)
std::cout << '\t' << lua_typename(L, lua_type(L, b + 1)) << '\n';
for (int i = 0; lua_pcall(L, 0, LUA_MULTRET, 0) == 0; ++i)
{
std::cout << "\nStack on iteration " << i << '\n';
for (int b = 0, e = lua_gettop(L); b != e; ++b)
std::cout << '\t' << lua_typename(L, lua_type(L, b + 1)) << '\n';
}
std::cout << "Before exit: " << lua_tostring(L, -1);
return 0;
}
关于您的问题,您期望lua_pcall
在每次循环迭代中都调用f
两次,但它的行为似乎不是这样的。下面是您提供的程序输出:
Stack before call:
function
function
- Function call, stack size: 1, parameter value: 2
Stack on iteration 0
function
- Function call, stack size: 1, parameter value: 1
Stack on iteration 1
Before exit: attempt to call a nil value
在第一次调用之前,堆栈上有两个函数(可能是f1
和f2
)。
- 在第一次调用中,只调用了
f2
。f1
仍然留在堆栈上。 - 在第二次调用中,只调用了
f1
。堆栈变为空。 - 在第三次调用中,
lua_pcall
失败并结束循环。
看起来每次调用时,都会从堆栈中弹出一个函数,所以显然我没有正确理解Lua库的工作原理。这是我(错误地)认为的情况:
- 在相同的
lua_State
指针上连续调用luaL_loadstring
,会将代码添加到Lua状态中,就好像我们在连接脚本。 - 在相同的
lua_State
指针上每次调用lua_pcall
,状态保持不变,就像它正在解释加载的脚本。
要执行(保持状态不变)我已经使用luaL_loadstring
添加到状态中的代码,您应该怎么做呢?
英文:
This is a simplified version of the code I'm testing:
int f(lua_State *L)
{
std::cout << std::format("- Function call, stack size: {}, parameter value: {}\n", lua_gettop(L), lua_tointeger(L, 1));
return 0;
}
int main()
{
lua_State *const L = luaL_newstate();
luaL_loadstring(L, "f1(1)");
luaL_loadstring(L, "f2(2)");
lua_register(L, "f1", f);
lua_register(L, "f2", f);
std::cout << "\nStack before call:\n";
for (int b = 0, e = lua_gettop(L); b != e; ++b)
std::cout << '\t' << lua_typename(L, lua_type(L, b + 1)) << '\n';
for (int i = 0; lua_pcall(L, 0, LUA_MULTRET, 0) == 0; ++i)
{
std::cout << "\nStack on iteration " << i << '\n';
for (int b = 0, e = lua_gettop(L); b != e; ++b)
std::cout << '\t' << lua_typename(L, lua_type(L, b + 1)) << '\n';
}
std::cout << "Before exit: " << lua_tostring(L, -1);
return 0;
}
I was expecting lua_pcall
to call f
twice each iteration of the loop, but this isn't how is it behaving, I'll paste the program output right below:
Stack before call:
function
function
- Function call, stack size: 1, parameter value: 2
Stack on iteration 0
function
- Function call, stack size: 1, parameter value: 1
Stack on iteration 1
Before exit: attempt to call a nil value
I have two functions on the stack before the first call (they might be f1
and f2
).
- On the first call only
f2
is called.f1
remains on the stack. - On the second call only
f1
is called. The stack is empty. - On the third call,
lua_pcall
fails and ends the loop.
Looks like on each call one function is popped from the stack, so obviously I'm not understanding how the Lua library works. This is what I (wrongly) thought:
- Consecutive calls to
luaL_loadstring
over the samelua_State
pointer, adds code to the lua state, as if we were concatenating scripts. - Each call to
lua_pcall
over the samelua_State
pointer, the state remains unchanged as if it was interpreting the loaded script.
What should I do in order to just execute (keep the state unchanged) the code I've added to the state with luaL_loadstring
?
答案1
得分: 1
在每次调用时,似乎从堆栈中弹出一个函数
这是正确的,而且你的代码基本上是正确的。问题是在执行 f1(1)
之后,lua_gettop(L)
变为 0,因此在下一次调用 lua_pcall
函数时,实际上调用了一个不正确的地址。你可以先检查堆栈顶部:
for (int i = 0; lua_gettop(L) > 0 && lua_pcall(L, 0, LUA_MULTRET, 0) == 0; ++i)
在 lua_pcall
函数中有一个 api_checknelems
行,但默认情况下它不执行任何操作,你需要在构建 Lua 库时定义 LUAI_ASSERT
。
出于同样的原因,你不应再尝试获取一个字符串:
std::cout << "Before exit: "; // << lua_tostring(L, -1);
为了只执行(保持状态不变)我使用
luaL_loadstring
添加到状态中的代码,我应该怎么做?
你可以使用 lua_pushvalue
在调用之前复制函数。
for (int i = 0; lua_pushvalue(L, -1), lua_pcall(L, 0, LUA_MULTRET, 0) == 0; ++i)
英文:
> Looks like on each call one function is popped from the stack
This is right, and your code is basically fine, the problem is after f1(1)
is executed lua_gettop(L)
becomes 0, so the next call to the lua_pcall
function, you actually call an incorrect address. You may check the top first:
for (int i = 0; lua_gettop(L) > 0 && lua_pcall(L, 0, LUA_MULTRET, 0) == 0; ++i)
There is a api_checknelems
line in the lua_pcall
function, but by default it does nothing, you need to define LUAI_ASSERT
while building the lua library.
For the same reason, you should not try to obtain a string anymore
std::cout << "Before exit: "; // << lua_tostring(L, -1);
> What should I do in order to just execute (keep the state unchanged) the code I've added to the state with luaL_loadstring?
You can use lua_pushvalue
to duplicate a function before calling it.
for (int i = 0; lua_pushvalue(L, -1), lua_pcall(L, 0, LUA_MULTRET, 0) == 0; ++i)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论