原型:void lua_call (lua_State *L, int nargs, int nresults);
功能:调用一个方法
调用一个函数必须按照以下的规则:
首先,将要调用的函数入栈;之后,将函数参数按顺序入栈,就是说第一个参数最先入栈。
最后调用lua_call;nargs是入栈的参数数。当函数被调用时弹出全部的参数和函数值。
当函数返回后函数结果会压入栈。结果的数量取决于nresults(lua_call的最后一个参数)。
除非nresults的值是LUA_MULTRET。以这种方式所有的函数结果都被入栈。由Lua管理栈空间中的这些返回值。
函数的结果按顺序入栈(第一个元素最先入栈),所以在调用完成后最后一个参数在栈顶。
Any error inside the called function is propagated upwards (with a longjmp).
在函数调用中产生的error会被向上传递(使用longjmp方式)。
The following example shows how the host program may do the equivalent to this Lua code:
下面的例子展示了如何使宿主程序做如下lua代码的功能:
a = f("how", t.x, 14)
这是在C中:
lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
lua_pushstring(L, "how"); /* 1st argument */
lua_getfield(L, LUA_GLOBALSINDEX, "t"); /* table to be indexed */
lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */
lua_remove(L, -2); /* remove 't' from the stack */
lua_pushinteger(L, 14); /* 3rd argument */
lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */
lua_setfield(L, LUA_GLOBALSINDEX, "a"); /* set global 'a' */
lua_State* L = lua_open();
lua_pushnumber( L, 211 );
lua_pushnumber( L, 2222 );
lua_newtable( L );
lua_close( L );
那么当执行完lua_newtable之后栈上有三个元素,大致就是这样:
211
222
table
现在211是第一个元素,index为1,不过LUA也可以用负数来表示,那么现在他是多少?
index -index value
1 -3 211
2 -2 222
3 -1 table
再看看如果我们要设置一个TABLE的值怎么做,用lua_settable或是lua_rawset,它们参数意义、以及准备工作都一样,-1是值,-2是键值
lua_settable( lua_state*, int )
第一个参数是要操作的脚本环境,第二个则是要操作的表在栈上的位置,一般的写法可能是这样
// 代码A
lua_getglobal( L, "myTable" ); // 获取要设置值的table
lua_pushstring( L, "hp" ); // "hp"在栈上的位置为-1
lua_pushnumber( L, 211 ); // "hp"在栈上的位置变为-2,而211则是-1
lua_settable( L, -3 ); // 值被正确的设置到全局变量(表)的myTable中
如果想把hp这个值设置到全局表中呢?一般通过调用lua_setglobal宏
lua_pushnumber( L, 211 );
lua_setglobal( L, "hp" );
就这么简单,不过我们来看看lua_setglobal这个宏
#define lua_setglobal(L,s) (lua_pushstring(L, s), lua_insert(L, -2), lua_settable(L, LUA_GLOBALSINDEX))
实际上我们上面的代码被替换成了
lua_pushnumber( L, 211 );
lua_pushstring( L, "hp" );
lua_insert( L, -2 ); // 这一步看上去或许比较诡异,实际上是把-1的值放到lua_insert的第二个参数所指的位置,然后这个位置后面的参数往上移
//这里实际上最终结果就是-1和-2对调,但从逻辑上并不是对调
lua_settable( L, LUA_GLOBALSINDEX ); // 这里为什么不用lua_rawset???
将上面的代码与代码A结合起来看,在lua_settable时index值不同,而它做的工作是如果发现index是LUA_GLOBALSINDEX 那么就取出全局表(还有一个LUA_REGISTERINDEX,类似),否则从stack上取元素,当然,这个栈位置取出的不是一个table就会失败。
所以代码A中指定的是-3是刚从全局表中取出的myTable表(这里假设他是一个table),上面的代码片段则是取出的全局表。
所以lua_settable的index是什么值都可以,只要它指向的是一个table
实际上lua中与c的接口也就主要在栈的操作上,基本上在写一个lua与C结合的程序时,最最需要做的工作就是明白当前栈上有什么元素以及它们的位置。
在纸上画出他们的位置,如果熟了,对于几句在一起有关联的lua调用则可以很快的看出栈的变化。比如
lua_gettable/lua_rawget
lua_pushstring( L, "hp" );
lua_gettable( L, LUA_GLOBALSINDEX );
只看第一句,栈顶是一个字符串,但两句放在一起,最终栈顶是一个全局表上一个名为hp的实际值
lua_pushstring( L, "hp" );
lua_pushnumber( L, 211 );
lua_settable( L, LUA_GLOBALSINDEX );
无论第二句pushnumber还是pushvalue,pushstring什么的,最终这三句执行之后对于栈来说是没有任何变化的,因为lua_settable/lua_rawset会移走-1和-2
总之,对于栈的变化,在看一个函数的文档时先看它参数又需要栈上那些位置的元素并正确设置栈上的值,
看清楚他会取栈上那些位置的元素作为这个lua api调用的使用并为之把正确的值放到栈上,
最后注意函数完成之后会清除/移走那些位置的元素。
lua_gettable