C 函数中调用Lua函数时,对于lua_pcall使用的困惑

来源:互联网 发布:js实现饼图 编辑:程序博客网 时间:2024/05/21 09:47

最近在学习使用Lua,也通过基本的语法知识完成了公司的一个关于配置文件参数合法性检查的小任务。虽然任务完成了,但对于一些函数的调用目的还是搞不明白,这两天再次重看了Manual Reference,稍微梳理出了一点眉目,记录在此。

首先看一段小小小程序

//test.lua

function printmsg()print("hello world")endx = 10

//test.c

#include <stdio.h>#include <unistd.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>int main(int argc, const char *argv[]){lua_State *L;if(NULL == (L = luaL_newstate())){perror("luaL_newstate failed");return -1;}luaL_openlibs(L);if(luaL_loadfile(L, "./test.lua")){perror("loadfile failed");return -1;}lua_pcall(L, 0, 0, 0); //一直这样用,但是一直不明白为什么一定要加这一句话lua_getglobal(L, "printmsg");lua_pcall(L, 0, 0, 0);lua_close(L);return 0;}


上面的代码就是在test.c中调用test.lua的函数printmsg函数


对于上面的C代码,我想大家都知道几个函数的大概作用:

luaL_newstate():创建一个新的Lua虚拟机

luaL_openlibs() :打开一些必要的库,比如print等

lua_loadfile():手册上写的是"This function uses lua_load to load the chunk in the filenamed filename." 而lua_load就是把编译过的chunk放在stack的顶部。理解chunk很重要,后面会具体讲到

lua_pcall : 执行栈上的函数调用


一开始我一直认为既然luaL_loadfile执行以后,就可以直接嗲用lua_getglobal获得test.lua中的函数,其实不然。手册中明确提到,lua_load把一个lua文件当作一个chunk编译后放到stack的栈顶,而什么是chunk呢?chunk就是一个可执行语句的组合,可以是一个文件也可以是一个string

“Lua handles a chunk as the body of an anonymous function with a variable number of arguments” 这是Lua对chunk也就是lua文件的处理方式,就是认为是一个可变参数的匿名函数。也就是说,调用后栈上有一个匿名函数,这个函数的body就是文件中所有的内容。

在luaL_loadfile后,调用lua_getop以及lua_type可以知道栈的大小为1,放在栈上的是一个fucntion类型的value。为什么loadfile后我们不能直接获取到printmsg这个函数呢,那是因为刚才提到的,loadfile仅仅视编译lua文件,并不执行这个文件,也就是说只是在栈上形成了一个匿名函数。只有执行这个函数一次,才会使得printmsg可以通过lua_getglobal获取,否则,全局变量是空的。我在手册上看到这样一句话:Lua在执行函数的时候,函数会实例化,获得的closure也是这个函数的最终值。其实不管视函数,还是其他类型,如果不执行的话,它们只是被编译,并不能在进程的空间种获取到他们,感觉就像c的库一样,他们的编译文件.so已经存在,但是如果你不调用它,那么库中所有的变量不能被实例化,调用者也就无法访问。其实pringmsg和x本质是一样的,只是他们类型不同而已。