在一个Lua脚本中,存在两个函数分别是mainFunctioncallbackFunction,其中callbackFunction作为参数传递给mainFunction,那么在C语言中如何确保lua_pcall调用的是mainFunction而非callbackFunction呢?

C语言调用Lua脚本函数

C和Lua之间进行通信的桥梁是lua_State中的堆栈,参数传递也是用堆栈来进行。

C语言调用Lua函数的接口是lua_pcall,其函数定义如下所示:

int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);

其中nargs是传入的参数个数,nresults是接收的返回值个数,errfunc是错误处理函数。

由于是通过堆栈传递数据,因此需要将函数名和参数都先压入堆栈才可以,并且需要确保最后一个参数位于栈顶。

如何确定调用的函数?

之前有一个疑惑的地方在于,如果一个Lua函数的参数是另一个函数,那么lua_pcall是怎么识别出执行的是哪个函数呢?

形如:

-- 定义回调函数
function callbackFunction()
    print("Callback function called")
end

-- 定义主函数,接受一个回调函数作为参数
function mainFunction(callback)
    print("Main function called")
    callback()
end

在C语言中调用mainFunction函数的方法如下所示:

#include <lua5.3/lauxlib.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <stdio.h>

int main()
{
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);

	// 加载并执行Lua脚本
	if (luaL_loadfile(L, "lua_c_callfunction.lua") || lua_pcall(L, 0, 0, 0))
	{
		fprintf(stderr, "Cannot run Lua file: %s\n", lua_tostring(L, -1));
		return 1;
	}

	// 获取主函数 mainFunction
	lua_getglobal(L, "mainFunction");

	// 获取回调函数 callbackFunction 并压入堆栈
	lua_getglobal(L, "callbackFunction");

	// 调用 mainFunction,传递1个参数(回调函数),期望0个返回值
	if (lua_pcall(L, 1, 0, 0) != 0)
	{
		fprintf(
			stderr, "Error calling mainFunction: %s\n", lua_tostring(L, -1));
		lua_pop(L, 1);  // 弹出错误信息
		return 1;
	}

	lua_close(L);
	return 0;
}

编译命令:gcc lua_c_callfunction.c -o lua_c_callfunction -llua5.3

在上述C代码中分别将两个函数使用lua_getglobal压入堆栈,那么怎么知道调用的是mainFunction而不是callbackFunction函数呢,问了几遍Copilot也没有答案。

直到修改了一次lua_pcall函数的参数个数,发现将其由1修改为0时,调用的是callbackFunction,才确定lua_pcall确定真正要调用函数的位置是从栈顶开始,经过指定的参数(第2个参数指定参数个数),然后会找到调用函数位置

在上述例子中,lua_pcall(L, 1, 0, 0)时调用的是mainFunctionlua_pcall(L, 0, 0, 0)时调用的是callbackFunction