英文:
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 
f2is called.f1remains on the stack. - On the second call  only 
f1is called. The stack is empty. - On the third call, 
lua_pcallfails 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_loadstringover the samelua_Statepointer, adds code to the lua state, as if we were concatenating scripts. - Each call to 
lua_pcallover the samelua_Statepointer, 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论