25.2 调用Lua函数 |
Lua作为配置文件的一个最大的长处在于它可以定义个被应用调用的函数。比如,你可以写一个应用程序来绘制一个函数的图像,使用Lua来定义这个函数。
使用API调用函数的方法是很简单的:首先,将被调用的函数入栈;第二,依次将所有参数入栈;第三,使用lua_pcall调用函数;最后,从栈中获取函数执行返回的结果。
看一个例子,假定我们的配置文件有下面这个函数:
function f (x, y)
return (x^2 * math.sin(y))/(1 - x)
end
并且我们想在C中对于给定的x,y计算z=f(x,y)的值。假如你已经打开了lua库并且运行了配置文件,你可以将这个调用封装成下面的C函数:
/* call a function `f' defined in Lua */
double f (double x, double y) {
double z;
/* push functions and arguments */
lua_getglobal(L, "f"); /* function to be called */
lua_pushnumber(L, x); /* push 1st argument */
lua_pushnumber(L, y); /* push 2nd argument */
/* do the call (2 arguments, 1 result) */
if (lua_pcall(L, 2, 1, 0) != 0)
error(L, "error running function `f': %s",
lua_tostring(L, -1));
/* retrieve result */
if (!lua_isnumber(L, -1))
error(L, "function `f' must return a number");
z = lua_tonumber(L, -1);
lua_pop(L, 1); /* pop returned value */
return z;
}
可以调用lua_pcall时指定参数的个数和返回结果的个数。第四个参数可以指定一个错误处理函数,我们下面再讨论它。和Lua中赋值操作一样,lua_pcall会根据你的要求调整返回结果的个数,多余的丢弃,少的用nil补足。在将结果入栈之前,lua_pcall会将栈内的函数和参数移除。如果函数返回多个结果,第一个结果被第一个入栈,因此如果有n个返回结果,第一个返回结果在栈中的位置为-n,最后一个返回结果在栈中的位置为-1。
如果lua_pcall运行时出现错误,lua_pcall会返回一个非0的结果。另外,他将错误信息入栈(仍然会先将函数和参数从栈中移除)。在将错误信息入栈之前,如果指定了错误处理函数,lua_pcall毁掉用错误处理函数。使用lua_pcall的最后一个参数来指定错误处理函数,0代表没有错误处理函数,也就是说最终的错误信息就是原始的错误信息。否则,那个参数应该是一个错误函数被加载的时候在栈中的索引,注意,在这种情况下,错误处理函数必须要在被调用函数和其参数入栈之前入栈。
对于一般错误,lua_pcall返回错误代码LUA_ERRRUN。有两种特殊情况,会返回特殊的错误代码,因为他们从来不会调用错误处理函数。第一种情况是,内存分配错误,对于这种错误,lua_pcall总是返回LUA_ERRMEM。第二种情况是,当Lua正在运行错误处理函数时发生错误,这种情况下,再次调用错误处理函数没有意义,所以lua_pcall立即返回错误代码LUA_ERRERR。