这里我们考虑2种情况:
1)C语言调用LUA的命名函数
2)C语言调用LUA中的匿名函数(一般匿名函数作为C函数的入参传给C)
情况1网络上一搜一大把,这里主要介绍情况2。
首先,我们知道几种常识:
1)C与LUA通过虚拟栈实现通讯
2)LUA调用C函数,在C函数中,栈中的内容为函数的参数,匿名函数作为函数的入参,自然也在栈中。
3)C中调用LUA函数(命名or匿名),先将函数入栈,再将参数逐个入栈,然后调用lua_pcall执行函数,执行完成后,将函数与参数出栈,将返回值入栈。
好了,介绍到这里,想要在C中调用匿名函数,似乎很简单,只要以下步骤:
1)从栈中取出函数,放入栈顶(拷贝或移动皆可)
2)继续放入匿名函数的参数
3)执行函数调用
4)获取返回值
5)栈恢复(返回值出栈)
int lua_test3(lua_State *L)
{
int num;
int top;
int ret;
top = lua_gettop(L);
printf("lua_test start: top = %d.\r\n", top);
/* 入参为:num,func,num */
/* 校验参数2是否是函数 */
if (!lua_isfunction(L, 2)) {
printf("LUA param 2 is not function!\r\n");
return -1;
}
/* 将参数2拷贝一份到栈顶 */
lua_pushvalue(L,2);
/* 函数参数入栈 */
lua_pushnumber(L, 999);
top = lua_gettop(L);
printf("lua_test before call: top = %d.\r\n", top);
/* 执行函数 */
ret= lua_pcall(L, 1, 1, 0);
top = lua_gettop(L);
printf("lua_test after call: top = %d.\r\n", top);
/* 获取返回值,注意转换类型 */
printf("callback result 1: %d!\r\n", (int)luaL_checknumber(L, -1));
/* 返回值出栈 */
lua_pop (L, 1);
/* 本函数的返回值入栈 */
lua_pushfstring(L, "%d", ret);
top = lua_gettop(L);
printf("lua_test end: top = %d.\r\n", top);
/* 返回1个返回值 */
return 1;
}
根据top的取值(栈的高度)我们可以看到,C函数参数会一直在栈底,假如我们要多次调用这个匿名函数,只要再次将匿名函数对象拷贝出来就可以了。假如我们在C函数中做很多复杂的操作,导致栈被清空了,这个时候匿名函数就不在栈里面了,怎么办?
可以把这个匿名函数保存起来!保存到LUA_REGISTRYINDEX注册表中,要用的时候再拿出来。
假设此时匿名函数变量已经在栈顶了,可以进行如下操作:
/* 将栈顶的匿名函数添加到表中 */
func_ref_id = luaL_ref(L, LUA_REGISTRYINDEX);
/* xxx:其他操作 */
/* 要用的时候,把该函数取出来,放入栈顶 */
lua_rawgeti(L, LUA_REGISTRYINDEX, func_ref_id);
/* 将参数入栈 */
lua_pushnumber(L, 888);
/* 调用函数 */
ret= lua_pcall(L, 1, 1, 0);
/* 返回值出栈 */
lua_pop (L, 1);
/* 解引用,如果这个函数不再需要了 */
luaL_unref(L, LUA_REGISTRYINDEX, func_ref_id);