lua c 栈操作

http://www.cnblogs.com/ringofthec/archive/2010/10/22/lua.html

http://blog.csdn.net/yangxianyy/article/details/5017631

C/C++与Lua交互(C实现的Lua编译器的例子)

   Lua库没有定义任何全局变量。它所有的状态保存在动态结构lua_State中,而且指向这个结构的指针作为所有Lua函数的一个参数。这样的实现方式使得Lua能够重入(reentrant)且为在多线程中的使用作好准备。
     创建一个state并将标准库载入之后,就可以着手解释用户的输入了。对于用户输入的每一行
while (fgets(buff, sizeof(buff), stdin) ,C程序首先调用luaL_loadbuffer编译这些Lua代码。如果没有错误,这个调用返回零并把编译之后的chunk压入栈。(记住,我们将在下一节中讨论魔法般的栈)之后,C程序调用lua_pcall,它将会把chunk从栈中弹出并在保护模式下运行它。和luaL_laodbuffer一样,lua_pcall在没有错误的情况下返回零。在有错误的情况下,这两个函数都将一条错误消息压入栈;我们可以用lua_tostring来得到这条信息、输出它,用lua_pop将它从栈中删除。




lua_call
void lua_call (lua_State *L, int nargs, int nresults);
调用一个函数。 
要调用一个函数请遵循以下协议:首先,要调用的函数应该被压入堆栈;接着,把需要传递给这个函数的参数按正序压栈;这是指第一个参数首先压栈。最后调用一下 lua_call; nargs 是你压入堆栈的参数个数。当函数调用完毕后,所有的参数以及函数本身都会出栈。而函数的返回值这时则被压入堆栈。返回值的个数将被调整为 nresults 个,除非 nresults 被设置成 LUA_MULTRET。在这种情况下,所有的返回值都被压入堆栈中。 Lua 会保证返回值都放入栈空间中。函数返回值将按正序压栈(第一个返回值首先压栈),因此在调用结束后,最后一个返回值将被放在栈顶。 
被调用函数内发生的错误将(通过 longjmp)一直上抛。 
下面的例子中,这行 Lua 代码等价于在宿主程序用 C 代码做一些工作: 
     a = f("how", t.x, 14)
这里是 C 里的代码: 
     lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* 将调用的函数 */
     lua_pushstring(L, "how");                          /* 第一个参数 */
     lua_getfield(L, LUA_GLOBALSINDEX, "t");          /* table 的索引 */
     lua_getfield(L, -1, "x");         /* 压入 t.x 的值(第 2 个参数)*/
     lua_remove(L, -2);                           /* 从堆栈中移去 't' */
     lua_pushinteger(L, 14);                           /* 第 3 个参数 */
     lua_call(L, 3, 1); /* 调用 'f',传入 3 个参数,并索取 1 个返回值 */
     lua_setfield(L, LUA_GLOBALSINDEX, "a");      /* 设置全局变量 'a' */
注意上面这段代码是“平衡”的:到了最后,堆栈恢复成原由的配置。这是一种良好的编程习惯。 
________________________________________
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 函数的类型。 
为了正确的和 Lua 通讯,C 函数必须使用下列定义了参数以及返回值传递方法的协议: C 函数通过 Lua 中的堆栈来接受参数,参数以正序入栈(第一个参数首先入栈)。因此,当函数开始的时候, lua_gettop(L) 可以返回函数收到的参数个数。第一个参数(如果有的话)在索引 1 的地方,而最后一个参数在索引 lua_gettop(L) 处。当需要向 Lua 返回值的时候,C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入),然后返回这些返回值的个数。在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。和 Lua 函数一样,从 Lua 中调用 C 函数也可以有很多返回值。 
下面这个例子中的函数将接收若干数字参数,并返回它们的平均数与和: 
     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* 参数的个数 */
       lua_Number sum = 0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushstring(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);   /* 第一个返回值 */
       lua_pushnumber(L, sum);     /* 第二个返回值 */
       return 2;                   /* 返回值的个数 */
     }
________________________________________
lua_checkstack
int lua_checkstack (lua_State *L, int extra);
确保堆栈上至少有 extra 个空位。如果不能把堆栈扩展到相应的尺寸,函数返回 false 。这个函数永远不会缩小堆栈;如果堆栈已经比需要的大了,那么就放在那里不会产生变化。 
________________________________________
lua_close
void lua_close (lua_State *L);
销毁指定 Lua 状态机中的所有对象(如果有垃圾收集相关的元方法的话,会调用它们),并且释放状态机中使用的所有动态内存。在一些平台上,你可以不必调用这个函数,因为当宿主程序结束的时候,所有的资源就自然被释放掉了。另一方面,长期运行的程序,比如一个后台程序或是一个 web 服务器,当不再需要它们的时候就应该释放掉相关状态机。这样可以避免状态机扩张的过大。 
________________________________________
lua_concat
void lua_concat (lua_State *L, int n);
连接栈顶的 n 个值,然后将这些值出栈,并把结果放在栈顶。如果 n 为 1 ,结果就是一个字符串放在栈上(即,函数什么都不做);如果 n 为 0 ,结果是一个空串。 连接依照 Lua 中创建语义完成(参见 §2.5.4 )。 
________________________________________
lua_cpcall
int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
以保护模式调用 C 函数 func 。 func 只有能从堆栈上拿到一个参数,就是包含有 ud 的 light userdata。当有错误时, lua_cpcall 返回和 lua_pcall 相同的错误代码,并在栈顶留下错误对象;否则它返回零,并不会修改堆栈。所有从 func 内返回的值都会被扔掉。 
________________________________________
lua_createtable
void lua_createtable (lua_State *L, int narr, int nrec);
创建一个新的空 table 压入堆栈。这个新 table 将被预分配 narr 个元素的数组空间以及 nrec 个元素的非数组空间。当你明确知道表中需要多少个元素时,预分配就非常有用。如果你不知道,可以使用函数 lua_newtable。 
________________________________________
lua_dump
int lua_dump (lua_State *L, lua_Writer writer, void *data);
把函数 dump 成二进制 chunk 。函数接收栈顶的 Lua 函数做参数,然后生成它的二进制 chunk 。若被 dump 出来的东西被再次加载,加载的结果就相当于原来的函数。当它在产生 chunk 的时候,lua_dump 通过调用函数 writer (参见 lua_Writer)来写入数据,后面的 data 参数会被传入 writer 。
最后一次由写入器 (writer) 返回值将作为这个函数的返回值返回; 0 表示没有错误。 
这个函数不会把 Lua 返回弹出堆栈。 
________________________________________
lua_equal
int lua_equal (lua_State *L, int index1, int index2);
如果依照 Lua 中 == 操作符语义,索引 index1 和 index2 中的值相同的话,返回 1 。否则返回 0 。如果任何一个索引无效也会返回 0。 
________________________________________
lua_error
int lua_error (lua_State *L);
产生一个 Lua 错误。错误信息(实际上可以是任何类型的 Lua 值)必须被置入栈顶。这个函数会做一次长跳转,因此它不会再返回。(参见 luaL_error)。 
________________________________________
lua_gc
int lua_gc (lua_State *L, int what, int data);
控制垃圾收集器。 
这个函数根据其参数 what 发起几种不同的任务: 
?        LUA_GCSTOP: 停止垃圾收集器。 
?        LUA_GCRESTART: 重启垃圾收集器。 
?        LUA_GCCOLLECT: 发起一次完整的垃圾收集循环。 
?        LUA_GCCOUNT: 返回 Lua 使用的内存总量(以 K 字节为单位)。 
?        LUA_GCCOUNTB: 返回当前内存使用量除以 1024 的余数。 
?        LUA_GCSTEP: 发起一步增量垃圾收集。步数由 data 控制(越大的值意味着越多步),而其具体含义(具体数字表示了多少)并未标准化。如果你想控制这个步数,必须实验性的测试 data 的值。如果这一步结束了一个垃圾收集周期,返回返回 1 。 
?        LUA_GCSETPAUSE: 把 data/100 设置为 garbage-collector pause 的新值(参见 §2.10)。函数返回以前的值。 
?        LUA_GCSETSTEPMUL: 把 arg/100 设置成 step multiplier (参见 §2.10)。函数返回以前的值。 
________________________________________
lua_getallocf
lua_Alloc lua_getallocf (lua_State *L, void **ud);
返回给定状态机的内存分配器函数。如果 ud 不是 NULL ,Lua 把调用 lua_newstate 时传入的那个指针放入 *ud 。 
________________________________________
lua_getfenv
void lua_getfenv (lua_State *L, int index);
把索引处值的环境表压入堆栈。 
________________________________________
lua_getfield
void lua_getfield (lua_State *L, int index, const char *k);
把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值。在 Lua 中,这个函数可能触发对应 "index" 事件的元方法(参见 §2.8)。 
________________________________________
lua_getglobal
void lua_getglobal (lua_State *L, const char *name);
把全局变量 name 里的值压入堆栈。这个是用一个宏定义出来的: 
     #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
________________________________________
lua_getmetatable
int lua_getmetatable (lua_State *L, int index);
把给定索引指向的值的元表压入堆栈。如果索引无效,或是这个值没有元表,函数将返回 0 并且不会向栈上压任何东西。 
________________________________________
lua_gettable
void lua_gettable (lua_State *L, int index);
把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值,而 k 则是栈顶放的值。 
这个函数会弹出堆栈上的 key (把结果放在栈上相同位置)。在 Lua 中,这个函数可能触发对应 "index" 事件的元方法(参见 §2.8)。 
________________________________________
lua_gettop
int lua_gettop (lua_State *L);
返回栈顶元素的索引。因为索引是从 1 开始编号的,所以这个结果等于堆栈上的元素个数(因此返回 0 表示堆栈为空)。 
________________________________________
lua_insert
void lua_insert (lua_State *L, int index);
把栈顶元素插入指定的有效索引处,并依次移动这个索引之上的元素。不要用伪索引来调用这个函数,因为伪索引不是真正指向堆栈上的位置。 
________________________________________
lua_Integer
typedef ptrdiff_t lua_Integer;
这个类型被用于 Lua API 接收整数值。 
缺省时这个被定义为 ptrdiff_t ,这个东西通常是机器能处理的最大整数类型。 
________________________________________
lua_isboolean
int lua_isboolean (lua_State *L, int index);
当给定索引的值类型为 boolean 时,返回 1 ,否则返回 0 。 
________________________________________
lua_iscfunction
int lua_iscfunction (lua_State *L, int index);
当给定索引的值是一个 C 函数时,返回 1 ,否则返回 0 。 
________________________________________
lua_isfunction
int lua_isfunction (lua_State *L, int index);
当给定索引的值是一个函数( C 或 Lua 函数均可)时,返回 1 ,否则返回 0 。 
________________________________________
lua_islightuserdata
int lua_islightuserdata (lua_State *L, int index);
当给定索引的值是一个 light userdata 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isnil
int lua_isnil (lua_State *L, int index);
当给定索引的值是 nil 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isnumber
int lua_isnumber (lua_State *L, int index);
当给定索引的值是一个数字,或是一个可转换为数字的字符串时,返回 1 ,否则返回 0 。 
________________________________________
lua_isstring
int lua_isstring (lua_State *L, int index);
当给定索引的值是一个字符串或是一个数字(数字总能转换成字符串)时,返回 1 ,否则返回 0 。 
________________________________________
lua_istable
int lua_istable (lua_State *L, int index);
当给定索引的值是一个 table 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isthread
int lua_isthread (lua_State *L, int index);
当给定索引的值是一个 thread 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isuserdata
int lua_isuserdata (lua_State *L, int index);
当给定索引的值是一个 userdata (无论是完整的 userdata 还是 light userdata )时,返回 1 ,否则返回 0 。 
________________________________________
lua_lessthan
int lua_lessthan (lua_State *L, int index1, int index2);
如果索引 index1 处的值小于索引 index2 处的值时,返回 1 ;否则返回 0 。其语义遵循 Lua 中的 < 操作符(就是说,有可能调用元方法)。如果任何一个索引无效,也会返回 0 。 
________________________________________
lua_load
int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname);
加载一个 Lua chunk 。如果没有错误, lua_load 把一个编译好的 chunk 作为一个 Lua 函数压入堆栈。否则,压入出错信息。 lua_load 的返回值可以是: 
?        0: 没有错误; 
?        LUA_ERRSYNTAX: 在预编译时碰到语法错误; 
?        LUA_ERRMEM: 内存分配错误。 
这个函数仅仅加栽 chunk ;而不会去运行它。 
lua_load 会自动检测 chunk 是文本的还是二进制的,然后做对应的加载操作(参见程序 luac)。 
lua_load 函数使用一个用户提供的 reader 函数来读取 chunk (参见 lua_Reader)。 data 参数会被传入读取器函数。 
chunkname 这个参数可以赋予 chunk 一个名字,这个名字被用于出错信息和调试信息(参见 §3.8)。 
________________________________________
lua_newstate
lua_State *lua_newstate (lua_Alloc f, void *ud);
创建的一个新的独立的状态机。如果创建不了(因为内存问题)返回 NULL 。参数 f 是一个分配器函数; Lua 将通过这个函数做状态机内所有的内存分配操作。第二个参数 ud ,这个指针将在每次调用分配器时被直接传入。 
________________________________________
lua_newtable
void lua_newtable (lua_State *L);
创建一个空 table ,并将之压入堆栈。它等价于 lua_createtable(L, 0, 0) 。 
________________________________________
lua_newthread
lua_State *lua_newthread (lua_State *L);
创建一个新线程,并将其压入堆栈,并返回维护这个线程的 lua_State 指针。这个函数返回的新状态机共享原有状态机中的所有对象(比如一些 table),但是它有独立的执行堆栈。 
没有显式的函数可以用来关闭或销毁掉一个线程。线程跟其它 Lua 对象一样是垃圾收集的条目之一。
________________________________________
lua_newuserdata
void *lua_newuserdata (lua_State *L, size_t size);
这个函数分配分配一块指定大小的内存块,把内存块地址作为一个完整的 userdata 压入堆栈,并返回这个地址。 
userdata 代表 Lua 中的 C 值。完整的 userdata 代表一块内存。它是一个对象(就像 table 那样的对象):你必须创建它,它有着自己的元表,而且它在被回收时,可以被监测到。一个完整的 userdata 只和它自己相等(在等于的原生作用下)。 
当 Lua 通过 gc 元方法回收一个完整的 userdata 时, Lua 调用这个元方法并把 userdata 标记为已终止。等到这个 userdata 再次被收集的时候,Lua 会释放掉相关的内存。 
________________________________________
lua_next
int lua_next (lua_State *L, int index);
从栈上弹出一个 key(键),然后把索引指定的表中 key-value(健值)对压入堆栈(指定 key 后面的下一 (next) 对)。如果表中以无更多元素,那么 lua_next 将返回 0 (什么也不压入堆栈)。 
典型的遍历方法是这样的: 
     /* table 放在索引 't' 处 */
     lua_pushnil(L);  /* 第一个 key */
     while (lua_next(L, t) != 0) {
       /* 用一下 'key' (在索引 -2 处) 和 'value' (在索引 -1 处) */
       printf("%s - %s/n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* 移除 'value' ;保留 'key' 做下一次叠代 */
       lua_pop(L, 1);
     }
在遍历一张表的时候,不要直接对 key 调用 lua_tolstring ,除非你知道这个 key 一定是一个字符串。调用 lua_tolstring 有可能改变给定索引位置的值;这会对下一次调用 lua_next 造成影响。
lua_Number
typedef double lua_Number;
Lua 中数字的类型。确省是 double ,但是你可以在 luaconf.h 中修改它。 
通过修改配置文件你可以改变 Lua 让它操作其它数字类型(例如:float 或是 long )。 
________________________________________
lua_objlen
size_t lua_objlen (lua_State *L, int index);
返回指定的索引处的值的长度。对于 string ,那就是字符串的长度;对于 table ,是取长度操作符 ('#') 的结果;对于 userdata ,就是为其分配的内存块的尺寸;对于其它值,为 0 。 
________________________________________
lua_pcall
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
以保护模式调用一个函数。 
nargs 和 nresults 的含义与 lua_call 中的相同。如果在调用过程中没有发生错误, lua_pcall 的行为和 lua_call 完全一致。但是,如果有错误发生的话, lua_pcall 会捕获它,然后把单一的值(错误信息)压入堆栈,然后返回错误码。同 lua_call 一样, lua_pcall 总是把函数本身和它的参数从栈上移除。 
如果 errfunc 是 0 ,返回在栈顶的错误信息就和原始错误信息完全一致。否则,errfunc 就被当成是错误处理函数在栈上的索引。(在当前的实现里,这个索引不能是伪索引。)在发生运行时错误时,这个函数会被调用而参数就是错误信息。错误处理函数的返回值将被 lua_pcall 作为出错信息返回在堆栈上。 
典型的用法中,错误处理函数被用来在出错信息上加上更多的调试信息,比如栈跟踪信息 (stack traceback) 。这些信息在 lua_pcall 返回后,因为栈已经展开 (unwound) ,所以收集不到了。 
lua_pcall 函数在调用成功时返回 0 ,否则返回以下(定义在 lua.h 中的)错误代码中的一个: 
?        LUA_ERRRUN: 运行时错误。 
?        LUA_ERRMEM: 内存分配错误。对于这种错,Lua 调用不了错误处理函数。 
?        LUA_ERRERR: 在运行错误处理函数时发生的错误。 
________________________________________
lua_pop
void lua_pop (lua_State *L, int n);
从堆栈中弹出 n 个元素。 
________________________________________
lua_pushboolean
void lua_pushboolean (lua_State *L, int b);
把 b 作为一个 boolean 值压入堆栈。 
________________________________________
lua_pushcclosure
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
把一个新的 C closure 压入堆栈。 
当创建了一个 C 函数后,你可以给它关联一些值,这样就是在创建一个 C closure (参见 §3.4);接下来无论函数何时被调用,这些值都可以被这个函数访问到。为了将一些值关联到一个 C 函数上,首先这些值需要先被压入堆栈(如果有多个值,第一个先压)。接下来调用 lua_pushcclosure 来创建出 closure 并把这个 C 函数压到堆栈上。参数 n 告之函数有多少个值需要关联到函数上。 lua_pushcclosure 也会把这些值从栈上弹出。 
________________________________________
lua_pushcfunction
void lua_pushcfunction (lua_State *L, lua_CFunction f);
将一个 C 函数压入堆栈。这个函数接收一个 C 函数指针,并将一个类型为 function 的 Lua 值压入堆栈。当这个栈定的值被调用时,将触发对应的 C 函数。 
注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值(参见 lua_CFunction)。 
lua_pushcfunction 是作为一个宏定义出现的: 
     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
________________________________________
lua_pushfstring
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
把一个格式化过的字符串压入堆栈,然后返回这个字符串的指针。它和 C 函数 sprintf 比较像,不过有一些重要的区别: 
?        摸你需要为结果分配空间:其结果是一个 Lua 字符串,由 Lua 来关心其内存分配(同时通过垃圾收集来释放内存)。 
?        这个转换非常的受限。不支持 flag ,宽度,或是指定精度。它只支持下面这些: '%%' (插入一个 '%'), '%s' (插入一个带零终止符的字符串,没有长度限制), '%f' (插入一个 lua_Number), '%p' (插入一个指针或是一个十六进制数), '%d' (插入一个 int), '%c' (把一个 int 作为一个字符插入)。 
________________________________________
lua_pushinteger
void lua_pushinteger (lua_State *L, lua_Integer n);
把 n 作为一个数字压栈。 
________________________________________
lua_pushlightuserdata
void lua_pushlightuserdata (lua_State *L, void *p);
把一个 light userdata 压栈。 
userdata 在 Lua 中表示一个 C 值。 light userdata 表示一个指针。它是一个像数字一样的值:你不需要专门创建它,它也没有独立的 metatable ,而且也不会被收集(因为从来不需要创建)。只要表示的 C 地址相同,两个 light userdata 就相等。 
________________________________________
lua_pushlstring
void lua_pushlstring (lua_State *L, const char *s, size_t len);
把指针 s 指向的长度为 len 的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串内可以保存有零字符。 
________________________________________
lua_pushnil
void lua_pushnil (lua_State *L);
把一个 nil 压栈。 
________________________________________
lua_pushnumber
void lua_pushnumber (lua_State *L, lua_Number n);
把一个数字 n 压栈。 
________________________________________
lua_pushstring
void lua_pushstring (lua_State *L, const char *s);
把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。 
________________________________________
lua_pushthread
int lua_pushthread (lua_State *L);
把 L 中提供的线程压栈。如果这个线程是当前状态机的主线程的话,返回 1 。 
________________________________________
lua_pushvalue
void lua_pushvalue (lua_State *L, int index);
把堆栈上给定有效处索引处的元素作一个拷贝压栈。 
________________________________________
lua_pushvfstring
const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);
等价于 lua_pushfstring,不过是用 va_list 接收参数,而不是用可变数量的实际参数。 
________________________________________
lua_rawequal
int lua_rawequal (lua_State *L, int index1, int index2);
如果两个索引 index1 和 index2 处的值简单地相等(不调用元方法)则返回 1 。否则返回 0 。如果任何一个索引无效也返回 0 。 
________________________________________
lua_rawget
void lua_rawget (lua_State *L, int index);
类似于 lua_gettable,但是作一次直接访问(不触发元方法)。 
________________________________________
lua_rawgeti
void lua_rawgeti (lua_State *L, int index, int n);
把 t[n] 的值压栈,这里的 t 是指给定索引 index 处的一个值。这是一个直接访问;就是说,它不会触发元方法。 
________________________________________
lua_rawset
void lua_rawset (lua_State *L, int index);
类似于 lua_settable,但是是作一个直接赋值(不触发元方法)。 
________________________________________
lua_rawseti
void lua_rawseti (lua_State *L, int index, int n);
等价于 t[n] = v,这里的 t 是指给定索引 index 处的一个值,而 v 是栈定的值。 
函数将把这个值弹出栈。赋值操作是直接的;就是说,不会触发元方法。 
________________________________________
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);
lua_load 用到的读取器函数,每次它需要一块新的 chunk 的时候, lua_load 就调用读取器,每次都会传入一个参数 data 。读取器需要返回含有新的 chunk 的一块内存的指针,并把 size 设为这块内存的大小。内存块必须在下一次函数被调用之前一直存在。读取器可以通过返回一个 NULL 来指示 chunk 结束。读取器可能返回多个块,每个块可以有任意的大于零的尺寸。 
________________________________________
lua_register
void lua_register (lua_State *L,
                   const char *name,
                   lua_CFunction f);
把 C 函数 f 设到全局变量 name 中。它通过一个宏定义: 
     #define lua_register(L,n,f) /
            (lua_pushcfunction(L, f), lua_setglobal(L, n))
________________________________________
lua_remove
void lua_remove (lua_State *L, int index);
从给定有效索引处移除一个元素,把这个索引之上的所有元素移下来填补上这个空隙。不能用伪索引来调用这个函数,因为伪索引并不指向真实的栈上的位置。 
________________________________________
lua_replace
void lua_replace (lua_State *L, int index);
把栈定元素移动到给定位置(并且把这个栈定元素弹出),不移动任何元素(因此在那个位置处的值被覆盖掉)。 
________________________________________
lua_resume
int lua_resume (lua_State *L, int narg);
在给定线程中启动或继续一个 coroutine 。 
要启动一个 coroutine 的话,首先你要创建一个新线程(参见 lua_newthread );然后把主函数和若干参数压到新线程的堆栈上;最后调用 lua_resume ,把 narg 设为参数的个数。这次调用会在 coroutine 挂起时或是结束运行后返回。当函数返回时,堆栈中会有传给 lua_yield 的所有值,或是主函数的所有返回值。如果 coroutine 切换时,lua_resume 返回 LUA_YIELD ,而当 coroutine 结束运行且没有任何错误时,返回 0 。如果有错则返回错误代码(参见 lua_pcall)。在发生错误的情况下,堆栈没有展开,因此你可以使用 debug API 来处理它。出错信息放在栈顶。要继续运行一个 coroutine 的话,你把需要传给 yield 作结果的返回值压入堆栈,然后调用 lua_resume 。 
________________________________________
lua_setallocf
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
把指定状态机的分配器函数换成带上指针 ud 的 f 。 
________________________________________
lua_setfenv
int lua_setfenv (lua_State *L, int index);
从堆栈上弹出一个 table 并把它设为指定索引处值的新环境。如果指定索引处的值即不是函数又不是线程或是 userdata , lua_setfenv 会返回 0 ,否则返回 1 。 
________________________________________
lua_setfield
void lua_setfield (lua_State *L, int index, const char *k);
做一个等价于 t[k] = v 的操作,这里 t 是给出的有效索引 index 处的值,而 v 是栈顶的那个值。 
这个函数将把这个值弹出堆栈。跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法(参见 §2.8)。 
________________________________________
lua_setglobal
void lua_setglobal (lua_State *L, const char *name);
从堆栈上弹出一个值,并将其设到全局变量 name 中。它由一个宏定义出来: 
     #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
________________________________________
lua_setmetatable
int lua_setmetatable (lua_State *L, int index);
把一个 table 弹出堆栈,并将其设为给定索引处的值的 metatable 。 
________________________________________
lua_settable
void lua_settable (lua_State *L, int index);
作一个等价于 t[k] = v 的操作,这里 t 是一个给定有效索引 index 处的值, v 指栈顶的值,而 k 是栈顶之下的那个值。 
这个函数会把键和值都从堆栈中弹出。和在 Lua 中一样,这个函数可能触发 "newindex" 事件的元方法(参见 §2.8)。 
________________________________________
lua_settop
void lua_settop (lua_State *L, int index);
参数允许传入任何可接受的索引以及 0 。它将把堆栈的栈顶设为这个索引。如果新的栈顶比原来的大,超出部分的新元素将被填为 nil 。如果 index 为 0 ,把栈上所有元素移除。 
________________________________________
lua_State
typedef struct lua_State lua_State;
一个不透明的结构,它保存了整个 Lua 解释器的状态。 Lua 库是完全可重入的:它没有任何全局变量。(译注:从 C 语法上来说,也不尽然。例如,在 table 的实现中用了一个静态全局变量 dummynode_ ,但这在正确使用时并不影响可重入性。只是万一你错误链接了 lua 库,不小心在同一进程空间中存在两份 lua 库实现的代码的话,多份 dummynode_ 不同的地址会导致一些问题。)所有的信息都保存在这个结构中。 
这个状态机的指针必须作为第一个参数传递给每一个库函数。 lua_newstate 是一个例外,这个函数会从头创建一个 Lua 状态机。 
________________________________________
lua_status
int lua_status (lua_State *L);
返回线程 L 的状态。 
正常的线程状态是 0 。当线程执行完毕或发生一个错误时,状态值是错误码。如果线程被挂起,状态为 LUA_YIELD 。 
________________________________________
lua_toboolean
int lua_toboolean (lua_State *L, int index);
把指定的索引处的的 Lua 值转换为一个 C 中的 boolean 值( 0 或是 1 )。和 Lua 中做的所有测试一样, lua_toboolean 会把任何不同于 false 和 nil 的值当作 1 返回;否则就返回 0 。如果用一个无效索引去调用也会返回 0 。(如果你想只接收真正的 boolean 值,就需要使用 lua_isboolean 来测试值的类型。) 
________________________________________
lua_tocfunction
lua_CFunction lua_tocfunction (lua_State *L, int index);
把给定索引处的 Lua 值转换为一个 C 函数。这个值必须是一个 C 函数;如果不是就返回 NULL 。 
________________________________________
lua_tointeger
lua_Integer lua_tointeger (lua_State *L, int idx);
把给定索引处的 Lua 值转换为 lua_Integer 这样一个有符号整数类型。这个 Lua 值必须是一个数字或是一个可以转换为数字的字符串(参见 §2.2.1);否则,lua_tointeger 返回 0 。 
如果数字不是一个整数,截断小数部分的方式没有被明确定义。 
________________________________________
lua_tolstring
const char *lua_tolstring (lua_State *L, int index, size_t *len);
把给定索引处的 Lua 值转换为一个 C 字符串。如果 len 不为 NULL ,它还把字符串长度设到 *len 中。这个 Lua 值必须是一个字符串或是一个数字;否则返回返回 NULL 。如果值是一个数字,lua_tolstring 还会把堆栈中的那个值的实际类型转换为一个字符串。(当遍历一个表的时候,把 lua_tolstring 作用在键上,这个转换有可能导致 lua_next 弄错。) 
lua_tolstring 返回 Lua 状态机中字符串的以对齐指针。这个字符串总能保证 ( C 要求的)最后一个字符为零 ('/0') ,而且它允许在字符串内包含多个这样的零。因为 Lua 中可能发生垃圾收集,所以不保证 lua_tolstring 返回的指针,在对应的值从堆栈中移除后依然有效。 
________________________________________
lua_tonumber
lua_Number lua_tonumber (lua_State *L, int index);
把给定索引处的 Lua 值转换为 lua_Number 这样一个 C 类型(参见 lua_Number )。这个 Lua 值必须是一个数字或是一个可转换为数字的字符串(参见 §2.2.1 );否则,lua_tonumber 返回 0 。 
________________________________________
lua_topointer
const void *lua_topointer (lua_State *L, int index);
把给定索引处的值转换为一般的 C 指针 (void*) 。这个值可以是一个 userdata ,table ,thread 或是一个 function ;否则,lua_topointer 返回 NULL 。不同的对象有不同的指针。不存在把指针再转回原有类型的方法。 
这个函数通常只为产生 debug 信息用。 
________________________________________
lua_tostring
const char *lua_tostring (lua_State *L, int index);
等价于 lua_tolstring ,而参数 len 设为 NULL 。 
________________________________________
lua_tothread
lua_State *lua_tothread (lua_State *L, int index);
把给定索引处的值转换为一个 Lua 线程(由 lua_State* 代表)。这个值必须是一个线程;否则函数返回 NULL 。 
________________________________________
lua_touserdata
void *lua_touserdata (lua_State *L, int index);
如果给定索引处的值是一个完整的 userdata ,函数返回内存块的地址。如果值是一个 light userdata ,那么就返回它表示的指针。否则,返回 NULL 。 
________________________________________
lua_type
int lua_type (lua_State *L, int index);
返回给定索引处的值的类型,当索引无效时则返回 LUA_TNONE (那是指一个指向堆栈上的空位置的索引)。 lua_type 返回的类型是一些个在 lua.h 中定义的常量: LUA_TNIL , LUA_TNUMBER , LUA_TBOOLEAN , LUA_TSTRING , LUA_TTABLE , LUA_TFUNCTION , LUA_TUSERDATA , LUA_TTHREAD , LUA_TLIGHTUSERDATA 。 
________________________________________
lua_typename
const char *lua_typename  (lua_State *L, int tp);
返回 tp 表示的类型名,这个 tp 必须是 lua_type 可能返回的值中之一。 
________________________________________
lua_Writer
typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);
由 lua_dump 用到的写入器函数。每次 lua_dump 产生了一块新的 chunk ,它都会调用写入器。传入要写入的缓存 (p) 和它的尺寸 (sz) ,还有 lua_dump 的参数 data 。 
写入器会返回一个错误码: 0 表示没有错误;别的值均表示一个错误,并且会让 lua_dump 停止再次调用写入器。 
________________________________________
lua_xmove
void lua_xmove (lua_State *from, lua_State *to, int n);
传递 同一个 全局状态机下不同线程中的值。 
这个函数会从 from 的堆栈中弹出 n 个值,然后把它们压入 to 的堆栈中。 
________________________________________
lua_yield
int lua_yield  (lua_State *L, int nresults);
切出一个 coroutine 。 
这个函数只能在一个 C 函数的返回表达式中调用。如下: 
     return lua_yield (L, nresults);
当一个 C 函数这样调用 lua_yield ,正在运行中的 coroutine 将从运行中挂起,然后启动这个 coroutine 用的那次对 lua_resume 的调用就返回了。参数 nresults 指的是堆栈中需要返回的结果个数,这些返回值将被传递给 lua_resume 。 
3.8 - 调试接口
Lua 没有内建的调试设施。取而代之的是提供了一些函数接口和钩子。利用这些接口,可以做出一些不同类型的调试器,性能分析器,或是其它一些需要从解释器中取到“内部信息”的工具。 
________________________________________
lua_Debug
typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  int currentline;            /* (l) */
  int nups;                   /* (u) upvalue 个数 */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* 私有部分 */
  其它域
} lua_Debug;
一个用来携带活动中函数的各种信息的结构。 lua_getstack 仅填写这个结构中的私有部分,这些部分以后会用到。调用 lua_getinfo 则可以填上 lua_Debug 中有用信息的那些域。 
lua_Debug 中的各个域有下列含义: 
?        source: 如果函数是定义在一个字符串中,source 就是这个字符串。如果函数定义在一个文件中, source 是一个以 


void lua_call (lua_State *L, int nargs, int nresults);
调用一个函数。 
要调用一个函数请遵循以下协议:首先,要调用的函数应该被压入堆栈;接着,把需要传递给这个函数的参数按正序压栈;这是指第一个参数首先压栈。最后调用一下 lua_call; nargs 是你压入堆栈的参数个数。当函数调用完毕后,所有的参数以及函数本身都会出栈。而函数的返回值这时则被压入堆栈。返回值的个数将被调整为 nresults 个,除非 nresults 被设置成 LUA_MULTRET。在这种情况下,所有的返回值都被压入堆栈中。 Lua 会保证返回值都放入栈空间中。函数返回值将按正序压栈(第一个返回值首先压栈),因此在调用结束后,最后一个返回值将被放在栈顶。 
被调用函数内发生的错误将(通过 longjmp)一直上抛。 
下面的例子中,这行 Lua 代码等价于在宿主程序用 C 代码做一些工作: 
     a = f("how", t.x, 14)
这里是 C 里的代码: 
     lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* 将调用的函数 */
     lua_pushstring(L, "how");                          /* 第一个参数 */
     lua_getfield(L, LUA_GLOBALSINDEX, "t");          /* table 的索引 */
     lua_getfield(L, -1, "x");         /* 压入 t.x 的值(第 2 个参数)*/
     lua_remove(L, -2);                           /* 从堆栈中移去 't' */
     lua_pushinteger(L, 14);                           /* 第 3 个参数 */
     lua_call(L, 3, 1); /* 调用 'f',传入 3 个参数,并索取 1 个返回值 */
     lua_setfield(L, LUA_GLOBALSINDEX, "a");      /* 设置全局变量 'a' */
注意上面这段代码是“平衡”的:到了最后,堆栈恢复成原由的配置。这是一种良好的编程习惯。 
________________________________________
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 函数的类型。 
为了正确的和 Lua 通讯,C 函数必须使用下列定义了参数以及返回值传递方法的协议: C 函数通过 Lua 中的堆栈来接受参数,参数以正序入栈(第一个参数首先入栈)。因此,当函数开始的时候, lua_gettop(L) 可以返回函数收到的参数个数。第一个参数(如果有的话)在索引 1 的地方,而最后一个参数在索引 lua_gettop(L) 处。当需要向 Lua 返回值的时候,C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入),然后返回这些返回值的个数。在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。和 Lua 函数一样,从 Lua 中调用 C 函数也可以有很多返回值。 
下面这个例子中的函数将接收若干数字参数,并返回它们的平均数与和: 
     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* 参数的个数 */
       lua_Number sum = 0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushstring(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);   /* 第一个返回值 */
       lua_pushnumber(L, sum);     /* 第二个返回值 */
       return 2;                   /* 返回值的个数 */
     }
________________________________________
lua_checkstack
int lua_checkstack (lua_State *L, int extra);
确保堆栈上至少有 extra 个空位。如果不能把堆栈扩展到相应的尺寸,函数返回 false 。这个函数永远不会缩小堆栈;如果堆栈已经比需要的大了,那么就放在那里不会产生变化。 
________________________________________
lua_close
void lua_close (lua_State *L);
销毁指定 Lua 状态机中的所有对象(如果有垃圾收集相关的元方法的话,会调用它们),并且释放状态机中使用的所有动态内存。在一些平台上,你可以不必调用这个函数,因为当宿主程序结束的时候,所有的资源就自然被释放掉了。另一方面,长期运行的程序,比如一个后台程序或是一个 web 服务器,当不再需要它们的时候就应该释放掉相关状态机。这样可以避免状态机扩张的过大。 
________________________________________
lua_concat
void lua_concat (lua_State *L, int n);
连接栈顶的 n 个值,然后将这些值出栈,并把结果放在栈顶。如果 n 为 1 ,结果就是一个字符串放在栈上(即,函数什么都不做);如果 n 为 0 ,结果是一个空串。 连接依照 Lua 中创建语义完成(参见 §2.5.4 )。 
________________________________________
lua_cpcall
int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
以保护模式调用 C 函数 func 。 func 只有能从堆栈上拿到一个参数,就是包含有 ud 的 light userdata。当有错误时, lua_cpcall 返回和 lua_pcall 相同的错误代码,并在栈顶留下错误对象;否则它返回零,并不会修改堆栈。所有从 func 内返回的值都会被扔掉。 
________________________________________
lua_createtable
void lua_createtable (lua_State *L, int narr, int nrec);
创建一个新的空 table 压入堆栈。这个新 table 将被预分配 narr 个元素的数组空间以及 nrec 个元素的非数组空间。当你明确知道表中需要多少个元素时,预分配就非常有用。如果你不知道,可以使用函数 lua_newtable。 
________________________________________
lua_dump
int lua_dump (lua_State *L, lua_Writer writer, void *data);
把函数 dump 成二进制 chunk 。函数接收栈顶的 Lua 函数做参数,然后生成它的二进制 chunk 。若被 dump 出来的东西被再次加载,加载的结果就相当于原来的函数。当它在产生 chunk 的时候,lua_dump 通过调用函数 writer (参见 lua_Writer)来写入数据,后面的 data 参数会被传入 writer 。
最后一次由写入器 (writer) 返回值将作为这个函数的返回值返回; 0 表示没有错误。 
这个函数不会把 Lua 返回弹出堆栈。 
________________________________________
lua_equal
int lua_equal (lua_State *L, int index1, int index2);
如果依照 Lua 中 == 操作符语义,索引 index1 和 index2 中的值相同的话,返回 1 。否则返回 0 。如果任何一个索引无效也会返回 0。 
________________________________________
lua_error
int lua_error (lua_State *L);
产生一个 Lua 错误。错误信息(实际上可以是任何类型的 Lua 值)必须被置入栈顶。这个函数会做一次长跳转,因此它不会再返回。(参见 luaL_error)。 
________________________________________
lua_gc
int lua_gc (lua_State *L, int what, int data);
控制垃圾收集器。 
这个函数根据其参数 what 发起几种不同的任务: 
?        LUA_GCSTOP: 停止垃圾收集器。 
?        LUA_GCRESTART: 重启垃圾收集器。 
?        LUA_GCCOLLECT: 发起一次完整的垃圾收集循环。 
?        LUA_GCCOUNT: 返回 Lua 使用的内存总量(以 K 字节为单位)。 
?        LUA_GCCOUNTB: 返回当前内存使用量除以 1024 的余数。 
?        LUA_GCSTEP: 发起一步增量垃圾收集。步数由 data 控制(越大的值意味着越多步),而其具体含义(具体数字表示了多少)并未标准化。如果你想控制这个步数,必须实验性的测试 data 的值。如果这一步结束了一个垃圾收集周期,返回返回 1 。 
?        LUA_GCSETPAUSE: 把 data/100 设置为 garbage-collector pause 的新值(参见 §2.10)。函数返回以前的值。 
?        LUA_GCSETSTEPMUL: 把 arg/100 设置成 step multiplier (参见 §2.10)。函数返回以前的值。 
________________________________________
lua_getallocf
lua_Alloc lua_getallocf (lua_State *L, void **ud);
返回给定状态机的内存分配器函数。如果 ud 不是 NULL ,Lua 把调用 lua_newstate 时传入的那个指针放入 *ud 。 
________________________________________
lua_getfenv
void lua_getfenv (lua_State *L, int index);
把索引处值的环境表压入堆栈。 
________________________________________
lua_getfield
void lua_getfield (lua_State *L, int index, const char *k);
把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值。在 Lua 中,这个函数可能触发对应 "index" 事件的元方法(参见 §2.8)。 
________________________________________
lua_getglobal
void lua_getglobal (lua_State *L, const char *name);
把全局变量 name 里的值压入堆栈。这个是用一个宏定义出来的: 
     #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
________________________________________
lua_getmetatable
int lua_getmetatable (lua_State *L, int index);
把给定索引指向的值的元表压入堆栈。如果索引无效,或是这个值没有元表,函数将返回 0 并且不会向栈上压任何东西。 
________________________________________
lua_gettable
void lua_gettable (lua_State *L, int index);
把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值,而 k 则是栈顶放的值。 
这个函数会弹出堆栈上的 key (把结果放在栈上相同位置)。在 Lua 中,这个函数可能触发对应 "index" 事件的元方法(参见 §2.8)。 
________________________________________
lua_gettop
int lua_gettop (lua_State *L);
返回栈顶元素的索引。因为索引是从 1 开始编号的,所以这个结果等于堆栈上的元素个数(因此返回 0 表示堆栈为空)。 
________________________________________
lua_insert
void lua_insert (lua_State *L, int index);
把栈顶元素插入指定的有效索引处,并依次移动这个索引之上的元素。不要用伪索引来调用这个函数,因为伪索引不是真正指向堆栈上的位置。 
________________________________________
lua_Integer
typedef ptrdiff_t lua_Integer;
这个类型被用于 Lua API 接收整数值。 
缺省时这个被定义为 ptrdiff_t ,这个东西通常是机器能处理的最大整数类型。 
________________________________________
lua_isboolean
int lua_isboolean (lua_State *L, int index);
当给定索引的值类型为 boolean 时,返回 1 ,否则返回 0 。 
________________________________________
lua_iscfunction
int lua_iscfunction (lua_State *L, int index);
当给定索引的值是一个 C 函数时,返回 1 ,否则返回 0 。 
________________________________________
lua_isfunction
int lua_isfunction (lua_State *L, int index);
当给定索引的值是一个函数( C 或 Lua 函数均可)时,返回 1 ,否则返回 0 。 
________________________________________
lua_islightuserdata
int lua_islightuserdata (lua_State *L, int index);
当给定索引的值是一个 light userdata 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isnil
int lua_isnil (lua_State *L, int index);
当给定索引的值是 nil 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isnumber
int lua_isnumber (lua_State *L, int index);
当给定索引的值是一个数字,或是一个可转换为数字的字符串时,返回 1 ,否则返回 0 。 
________________________________________
lua_isstring
int lua_isstring (lua_State *L, int index);
当给定索引的值是一个字符串或是一个数字(数字总能转换成字符串)时,返回 1 ,否则返回 0 。 
________________________________________
lua_istable
int lua_istable (lua_State *L, int index);
当给定索引的值是一个 table 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isthread
int lua_isthread (lua_State *L, int index);
当给定索引的值是一个 thread 时,返回 1 ,否则返回 0 。 
________________________________________
lua_isuserdata
int lua_isuserdata (lua_State *L, int index);
当给定索引的值是一个 userdata (无论是完整的 userdata 还是 light userdata )时,返回 1 ,否则返回 0 。 
________________________________________
lua_lessthan
int lua_lessthan (lua_State *L, int index1, int index2);
如果索引 index1 处的值小于索引 index2 处的值时,返回 1 ;否则返回 0 。其语义遵循 Lua 中的 < 操作符(就是说,有可能调用元方法)。如果任何一个索引无效,也会返回 0 。 
________________________________________
lua_load
int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname);
加载一个 Lua chunk 。如果没有错误, lua_load 把一个编译好的 chunk 作为一个 Lua 函数压入堆栈。否则,压入出错信息。 lua_load 的返回值可以是: 
?        0: 没有错误; 
?        LUA_ERRSYNTAX: 在预编译时碰到语法错误; 
?        LUA_ERRMEM: 内存分配错误。 
这个函数仅仅加栽 chunk ;而不会去运行它。 
lua_load 会自动检测 chunk 是文本的还是二进制的,然后做对应的加载操作(参见程序 luac)。 
lua_load 函数使用一个用户提供的 reader 函数来读取 chunk (参见 lua_Reader)。 data 参数会被传入读取器函数。 
chunkname 这个参数可以赋予 chunk 一个名字,这个名字被用于出错信息和调试信息(参见 §3.8)。 
________________________________________
lua_newstate
lua_State *lua_newstate (lua_Alloc f, void *ud);
创建的一个新的独立的状态机。如果创建不了(因为内存问题)返回 NULL 。参数 f 是一个分配器函数; Lua 将通过这个函数做状态机内所有的内存分配操作。第二个参数 ud ,这个指针将在每次调用分配器时被直接传入。 
________________________________________
lua_newtable
void lua_newtable (lua_State *L);
创建一个空 table ,并将之压入堆栈。它等价于 lua_createtable(L, 0, 0) 。 
________________________________________
lua_newthread
lua_State *lua_newthread (lua_State *L);
创建一个新线程,并将其压入堆栈,并返回维护这个线程的 lua_State 指针。这个函数返回的新状态机共享原有状态机中的所有对象(比如一些 table),但是它有独立的执行堆栈。 
没有显式的函数可以用来关闭或销毁掉一个线程。线程跟其它 Lua 对象一样是垃圾收集的条目之一。
________________________________________
lua_newuserdata
void *lua_newuserdata (lua_State *L, size_t size);
这个函数分配分配一块指定大小的内存块,把内存块地址作为一个完整的 userdata 压入堆栈,并返回这个地址。 
userdata 代表 Lua 中的 C 值。完整的 userdata 代表一块内存。它是一个对象(就像 table 那样的对象):你必须创建它,它有着自己的元表,而且它在被回收时,可以被监测到。一个完整的 userdata 只和它自己相等(在等于的原生作用下)。 
当 Lua 通过 gc 元方法回收一个完整的 userdata 时, Lua 调用这个元方法并把 userdata 标记为已终止。等到这个 userdata 再次被收集的时候,Lua 会释放掉相关的内存。 
________________________________________
lua_next
int lua_next (lua_State *L, int index);
从栈上弹出一个 key(键),然后把索引指定的表中 key-value(健值)对压入堆栈(指定 key 后面的下一 (next) 对)。如果表中以无更多元素,那么 lua_next 将返回 0 (什么也不压入堆栈)。 
典型的遍历方法是这样的: 
     /* table 放在索引 't' 处 */
     lua_pushnil(L);  /* 第一个 key */
     while (lua_next(L, t) != 0) {
       /* 用一下 'key' (在索引 -2 处) 和 'value' (在索引 -1 处) */
       printf("%s - %s/n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* 移除 'value' ;保留 'key' 做下一次叠代 */
       lua_pop(L, 1);
     }
在遍历一张表的时候,不要直接对 key 调用 lua_tolstring ,除非你知道这个 key 一定是一个字符串。调用 lua_tolstring 有可能改变给定索引位置的值;这会对下一次调用 lua_next 造成影响。
lua_Number
typedef double lua_Number;
Lua 中数字的类型。确省是 double ,但是你可以在 luaconf.h 中修改它。 
通过修改配置文件你可以改变 Lua 让它操作其它数字类型(例如:float 或是 long )。 
________________________________________
lua_objlen
size_t lua_objlen (lua_State *L, int index);
返回指定的索引处的值的长度。对于 string ,那就是字符串的长度;对于 table ,是取长度操作符 ('#') 的结果;对于 userdata ,就是为其分配的内存块的尺寸;对于其它值,为 0 。 
________________________________________
lua_pcall
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
以保护模式调用一个函数。 
nargs 和 nresults 的含义与 lua_call 中的相同。如果在调用过程中没有发生错误, lua_pcall 的行为和 lua_call 完全一致。但是,如果有错误发生的话, lua_pcall 会捕获它,然后把单一的值(错误信息)压入堆栈,然后返回错误码。同 lua_call 一样, lua_pcall 总是把函数本身和它的参数从栈上移除。 
如果 errfunc 是 0 ,返回在栈顶的错误信息就和原始错误信息完全一致。否则,errfunc 就被当成是错误处理函数在栈上的索引。(在当前的实现里,这个索引不能是伪索引。)在发生运行时错误时,这个函数会被调用而参数就是错误信息。错误处理函数的返回值将被 lua_pcall 作为出错信息返回在堆栈上。 
典型的用法中,错误处理函数被用来在出错信息上加上更多的调试信息,比如栈跟踪信息 (stack traceback) 。这些信息在 lua_pcall 返回后,因为栈已经展开 (unwound) ,所以收集不到了。 
lua_pcall 函数在调用成功时返回 0 ,否则返回以下(定义在 lua.h 中的)错误代码中的一个: 
?        LUA_ERRRUN: 运行时错误。 
?        LUA_ERRMEM: 内存分配错误。对于这种错,Lua 调用不了错误处理函数。 
?        LUA_ERRERR: 在运行错误处理函数时发生的错误。 
________________________________________
lua_pop
void lua_pop (lua_State *L, int n);
从堆栈中弹出 n 个元素。 
________________________________________
lua_pushboolean
void lua_pushboolean (lua_State *L, int b);
把 b 作为一个 boolean 值压入堆栈。 
________________________________________
lua_pushcclosure
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
把一个新的 C closure 压入堆栈。 
当创建了一个 C 函数后,你可以给它关联一些值,这样就是在创建一个 C closure (参见 §3.4);接下来无论函数何时被调用,这些值都可以被这个函数访问到。为了将一些值关联到一个 C 函数上,首先这些值需要先被压入堆栈(如果有多个值,第一个先压)。接下来调用 lua_pushcclosure 来创建出 closure 并把这个 C 函数压到堆栈上。参数 n 告之函数有多少个值需要关联到函数上。 lua_pushcclosure 也会把这些值从栈上弹出。 
________________________________________
lua_pushcfunction
void lua_pushcfunction (lua_State *L, lua_CFunction f);
将一个 C 函数压入堆栈。这个函数接收一个 C 函数指针,并将一个类型为 function 的 Lua 值压入堆栈。当这个栈定的值被调用时,将触发对应的 C 函数。 
注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值(参见 lua_CFunction)。 
lua_pushcfunction 是作为一个宏定义出现的: 
     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
________________________________________
lua_pushfstring
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
把一个格式化过的字符串压入堆栈,然后返回这个字符串的指针。它和 C 函数 sprintf 比较像,不过有一些重要的区别: 
?        摸你需要为结果分配空间:其结果是一个 Lua 字符串,由 Lua 来关心其内存分配(同时通过垃圾收集来释放内存)。 
?        这个转换非常的受限。不支持 flag ,宽度,或是指定精度。它只支持下面这些: '%%' (插入一个 '%'), '%s' (插入一个带零终止符的字符串,没有长度限制), '%f' (插入一个 lua_Number), '%p' (插入一个指针或是一个十六进制数), '%d' (插入一个 int), '%c' (把一个 int 作为一个字符插入)。 
________________________________________
lua_pushinteger
void lua_pushinteger (lua_State *L, lua_Integer n);
把 n 作为一个数字压栈。 
________________________________________
lua_pushlightuserdata
void lua_pushlightuserdata (lua_State *L, void *p);
把一个 light userdata 压栈。 
userdata 在 Lua 中表示一个 C 值。 light userdata 表示一个指针。它是一个像数字一样的值:你不需要专门创建它,它也没有独立的 metatable ,而且也不会被收集(因为从来不需要创建)。只要表示的 C 地址相同,两个 light userdata 就相等。 
________________________________________
lua_pushlstring
void lua_pushlstring (lua_State *L, const char *s, size_t len);
把指针 s 指向的长度为 len 的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串内可以保存有零字符。 
________________________________________
lua_pushnil
void lua_pushnil (lua_State *L);
把一个 nil 压栈。 
________________________________________
lua_pushnumber
void lua_pushnumber (lua_State *L, lua_Number n);
把一个数字 n 压栈。 
________________________________________
lua_pushstring
void lua_pushstring (lua_State *L, const char *s);
把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。 
________________________________________
lua_pushthread
int lua_pushthread (lua_State *L);
把 L 中提供的线程压栈。如果这个线程是当前状态机的主线程的话,返回 1 。 
________________________________________
lua_pushvalue
void lua_pushvalue (lua_State *L, int index);
把堆栈上给定有效处索引处的元素作一个拷贝压栈。 
________________________________________
lua_pushvfstring
const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);
等价于 lua_pushfstring,不过是用 va_list 接收参数,而不是用可变数量的实际参数。 
________________________________________
lua_rawequal
int lua_rawequal (lua_State *L, int index1, int index2);
如果两个索引 index1 和 index2 处的值简单地相等(不调用元方法)则返回 1 。否则返回 0 。如果任何一个索引无效也返回 0 。 
________________________________________
lua_rawget
void lua_rawget (lua_State *L, int index);
类似于 lua_gettable,但是作一次直接访问(不触发元方法)。 
________________________________________
lua_rawgeti
void lua_rawgeti (lua_State *L, int index, int n);
把 t[n] 的值压栈,这里的 t 是指给定索引 index 处的一个值。这是一个直接访问;就是说,它不会触发元方法。 
________________________________________
lua_rawset
void lua_rawset (lua_State *L, int index);
类似于 lua_settable,但是是作一个直接赋值(不触发元方法)。 
________________________________________
lua_rawseti
void lua_rawseti (lua_State *L, int index, int n);
等价于 t[n] = v,这里的 t 是指给定索引 index 处的一个值,而 v 是栈定的值。 
函数将把这个值弹出栈。赋值操作是直接的;就是说,不会触发元方法。 
________________________________________
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);
lua_load 用到的读取器函数,每次它需要一块新的 chunk 的时候, lua_load 就调用读取器,每次都会传入一个参数 data 。读取器需要返回含有新的 chunk 的一块内存的指针,并把 size 设为这块内存的大小。内存块必须在下一次函数被调用之前一直存在。读取器可以通过返回一个 NULL 来指示 chunk 结束。读取器可能返回多个块,每个块可以有任意的大于零的尺寸。 
________________________________________
lua_register
void lua_register (lua_State *L,
                   const char *name,
                   lua_CFunction f);
把 C 函数 f 设到全局变量 name 中。它通过一个宏定义: 
     #define lua_register(L,n,f) /
            (lua_pushcfunction(L, f), lua_setglobal(L, n))
________________________________________
lua_remove
void lua_remove (lua_State *L, int index);
从给定有效索引处移除一个元素,把这个索引之上的所有元素移下来填补上这个空隙。不能用伪索引来调用这个函数,因为伪索引并不指向真实的栈上的位置。 
________________________________________
lua_replace
void lua_replace (lua_State *L, int index);
把栈定元素移动到给定位置(并且把这个栈定元素弹出),不移动任何元素(因此在那个位置处的值被覆盖掉)。 
________________________________________
lua_resume
int lua_resume (lua_State *L, int narg);
在给定线程中启动或继续一个 coroutine 。 
要启动一个 coroutine 的话,首先你要创建一个新线程(参见 lua_newthread );然后把主函数和若干参数压到新线程的堆栈上;最后调用 lua_resume ,把 narg 设为参数的个数。这次调用会在 coroutine 挂起时或是结束运行后返回。当函数返回时,堆栈中会有传给 lua_yield 的所有值,或是主函数的所有返回值。如果 coroutine 切换时,lua_resume 返回 LUA_YIELD ,而当 coroutine 结束运行且没有任何错误时,返回 0 。如果有错则返回错误代码(参见 lua_pcall)。在发生错误的情况下,堆栈没有展开,因此你可以使用 debug API 来处理它。出错信息放在栈顶。要继续运行一个 coroutine 的话,你把需要传给 yield 作结果的返回值压入堆栈,然后调用 lua_resume 。 
________________________________________
lua_setallocf
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
把指定状态机的分配器函数换成带上指针 ud 的 f 。 
________________________________________
lua_setfenv
int lua_setfenv (lua_State *L, int index);
从堆栈上弹出一个 table 并把它设为指定索引处值的新环境。如果指定索引处的值即不是函数又不是线程或是 userdata , lua_setfenv 会返回 0 ,否则返回 1 。 
________________________________________
lua_setfield
void lua_setfield (lua_State *L, int index, const char *k);
做一个等价于 t[k] = v 的操作,这里 t 是给出的有效索引 index 处的值,而 v 是栈顶的那个值。 
这个函数将把这个值弹出堆栈。跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法(参见 §2.8)。 
________________________________________
lua_setglobal
void lua_setglobal (lua_State *L, const char *name);
从堆栈上弹出一个值,并将其设到全局变量 name 中。它由一个宏定义出来: 
     #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
________________________________________
lua_setmetatable
int lua_setmetatable (lua_State *L, int index);
把一个 table 弹出堆栈,并将其设为给定索引处的值的 metatable 。 
________________________________________
lua_settable
void lua_settable (lua_State *L, int index);
作一个等价于 t[k] = v 的操作,这里 t 是一个给定有效索引 index 处的值, v 指栈顶的值,而 k 是栈顶之下的那个值。 
这个函数会把键和值都从堆栈中弹出。和在 Lua 中一样,这个函数可能触发 "newindex" 事件的元方法(参见 §2.8)。 
________________________________________
lua_settop
void lua_settop (lua_State *L, int index);
参数允许传入任何可接受的索引以及 0 。它将把堆栈的栈顶设为这个索引。如果新的栈顶比原来的大,超出部分的新元素将被填为 nil 。如果 index 为 0 ,把栈上所有元素移除。 
________________________________________
lua_State
typedef struct lua_State lua_State;
一个不透明的结构,它保存了整个 Lua 解释器的状态。 Lua 库是完全可重入的:它没有任何全局变量。(译注:从 C 语法上来说,也不尽然。例如,在 table 的实现中用了一个静态全局变量 dummynode_ ,但这在正确使用时并不影响可重入性。只是万一你错误链接了 lua 库,不小心在同一进程空间中存在两份 lua 库实现的代码的话,多份 dummynode_ 不同的地址会导致一些问题。)所有的信息都保存在这个结构中。 
这个状态机的指针必须作为第一个参数传递给每一个库函数。 lua_newstate 是一个例外,这个函数会从头创建一个 Lua 状态机。 
________________________________________
lua_status
int lua_status (lua_State *L);
返回线程 L 的状态。 
正常的线程状态是 0 。当线程执行完毕或发生一个错误时,状态值是错误码。如果线程被挂起,状态为 LUA_YIELD 。 
________________________________________
lua_toboolean
int lua_toboolean (lua_State *L, int index);
把指定的索引处的的 Lua 值转换为一个 C 中的 boolean 值( 0 或是 1 )。和 Lua 中做的所有测试一样, lua_toboolean 会把任何不同于 false 和 nil 的值当作 1 返回;否则就返回 0 。如果用一个无效索引去调用也会返回 0 。(如果你想只接收真正的 boolean 值,就需要使用 lua_isboolean 来测试值的类型。) 
________________________________________
lua_tocfunction
lua_CFunction lua_tocfunction (lua_State *L, int index);
把给定索引处的 Lua 值转换为一个 C 函数。这个值必须是一个 C 函数;如果不是就返回 NULL 。 
________________________________________
lua_tointeger
lua_Integer lua_tointeger (lua_State *L, int idx);
把给定索引处的 Lua 值转换为 lua_Integer 这样一个有符号整数类型。这个 Lua 值必须是一个数字或是一个可以转换为数字的字符串(参见 §2.2.1);否则,lua_tointeger 返回 0 。 
如果数字不是一个整数,截断小数部分的方式没有被明确定义。 
________________________________________
lua_tolstring
const char *lua_tolstring (lua_State *L, int index, size_t *len);
把给定索引处的 Lua 值转换为一个 C 字符串。如果 len 不为 NULL ,它还把字符串长度设到 *len 中。这个 Lua 值必须是一个字符串或是一个数字;否则返回返回 NULL 。如果值是一个数字,lua_tolstring 还会把堆栈中的那个值的实际类型转换为一个字符串。(当遍历一个表的时候,把 lua_tolstring 作用在键上,这个转换有可能导致 lua_next 弄错。) 
lua_tolstring 返回 Lua 状态机中字符串的以对齐指针。这个字符串总能保证 ( C 要求的)最后一个字符为零 ('/0') ,而且它允许在字符串内包含多个这样的零。因为 Lua 中可能发生垃圾收集,所以不保证 lua_tolstring 返回的指针,在对应的值从堆栈中移除后依然有效。 
________________________________________
lua_tonumber
lua_Number lua_tonumber (lua_State *L, int index);
把给定索引处的 Lua 值转换为 lua_Number 这样一个 C 类型(参见 lua_Number )。这个 Lua 值必须是一个数字或是一个可转换为数字的字符串(参见 §2.2.1 );否则,lua_tonumber 返回 0 。 
________________________________________
lua_topointer
const void *lua_topointer (lua_State *L, int index);
把给定索引处的值转换为一般的 C 指针 (void*) 。这个值可以是一个 userdata ,table ,thread 或是一个 function ;否则,lua_topointer 返回 NULL 。不同的对象有不同的指针。不存在把指针再转回原有类型的方法。 
这个函数通常只为产生 debug 信息用。 
________________________________________
lua_tostring
const char *lua_tostring (lua_State *L, int index);
等价于 lua_tolstring ,而参数 len 设为 NULL 。 
________________________________________
lua_tothread
lua_State *lua_tothread (lua_State *L, int index);
把给定索引处的值转换为一个 Lua 线程(由 lua_State* 代表)。这个值必须是一个线程;否则函数返回 NULL 。 
________________________________________
lua_touserdata
void *lua_touserdata (lua_State *L, int index);
如果给定索引处的值是一个完整的 userdata ,函数返回内存块的地址。如果值是一个 light userdata ,那么就返回它表示的指针。否则,返回 NULL 。 
________________________________________
lua_type
int lua_type (lua_State *L, int index);
返回给定索引处的值的类型,当索引无效时则返回 LUA_TNONE (那是指一个指向堆栈上的空位置的索引)。 lua_type 返回的类型是一些个在 lua.h 中定义的常量: LUA_TNIL , LUA_TNUMBER , LUA_TBOOLEAN , LUA_TSTRING , LUA_TTABLE , LUA_TFUNCTION , LUA_TUSERDATA , LUA_TTHREAD , LUA_TLIGHTUSERDATA 。 
________________________________________
lua_typename
const char *lua_typename  (lua_State *L, int tp);
返回 tp 表示的类型名,这个 tp 必须是 lua_type 可能返回的值中之一。 
________________________________________
lua_Writer
typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);
由 lua_dump 用到的写入器函数。每次 lua_dump 产生了一块新的 chunk ,它都会调用写入器。传入要写入的缓存 (p) 和它的尺寸 (sz) ,还有 lua_dump 的参数 data 。 
写入器会返回一个错误码: 0 表示没有错误;别的值均表示一个错误,并且会让 lua_dump 停止再次调用写入器。 
________________________________________
lua_xmove
void lua_xmove (lua_State *from, lua_State *to, int n);
传递 同一个 全局状态机下不同线程中的值。 
这个函数会从 from 的堆栈中弹出 n 个值,然后把它们压入 to 的堆栈中。 
________________________________________
lua_yield
int lua_yield  (lua_State *L, int nresults);
切出一个 coroutine 。 
这个函数只能在一个 C 函数的返回表达式中调用。如下: 
     return lua_yield (L, nresults);
当一个 C 函数这样调用 lua_yield ,正在运行中的 coroutine 将从运行中挂起,然后启动这个 coroutine 用的那次对 lua_resume 的调用就返回了。参数 nresults 指的是堆栈中需要返回的结果个数,这些返回值将被传递给 lua_resume 。 
3.8 - 调试接口
Lua 没有内建的调试设施。取而代之的是提供了一些函数接口和钩子。利用这些接口,可以做出一些不同类型的调试器,性能分析器,或是其它一些需要从解释器中取到“内部信息”的工具。 
________________________________________
lua_Debug
typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  int currentline;            /* (l) */
  int nups;                   /* (u) upvalue 个数 */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* 私有部分 */
  其它域
} lua_Debug;
一个用来携带活动中函数的各种信息的结构。 lua_getstack 仅填写这个结构中的私有部分,这些部分以后会用到。调用 lua_getinfo 则可以填上 lua_Debug 中有用信息的那些域。 
lua_Debug 中的各个域有下列含义: 
?        source: 如果函数是定义在一个字符串中,source 就是这个字符串。如果函数定义在一个文件中, source 是一个以 
'@'  开头的文件名。 
?        short_src: 一个“可打印版本”的 source,用于出错信息。 
?        linedefined: 函数定义开始处的行号。 
?        lastlinedefined: 函数定义结束处的行号。 
?        what: 如果函数是一个 Lua 函数,则为一个字符串 "Lua" ;如果是一个 C 函数,则为 "C";如果它是一个 chunk 的主体部分,则为 "main";如果是一个作了尾调用的函数,则为 "tail" 。别的情况下,Lua 没有关于函数的别的信息。 
?        currentline: 给定函数正在执行的那一行。当提供不了行号信息的时候,currentline 被设为 -1 。 
?        name: 给定函数的一个合理的名字。因为 Lua 中的函数也是一个值,所以它们没有固定的名字:一些函数可能是全局复合变量的值,另一些可能仅仅只是被保存在一个 table 中。 lua_getinfo 函数会检查函数是这样被调用的,以此来找到一个适合的名字。如果它找不到名字,name 就被设置为 NULL 。 
?        namewhat: 结实 name 域。 namewhat 的值可以是 "global", "local", "method", "field", "upvalue", 或是 "" (空串)。这取决于函数怎样被调用。(Lua 用空串表示其它选项都不符合) 
?        nups: 函数的 upvalue 的个数。 
________________________________________
lua_gethook
lua_Hook lua_gethook (lua_State *L);
返回当前的钩子函数。 
________________________________________
lua_gethookcount
int lua_gethookcount (lua_State *L);
返回当前钩子记数。 
________________________________________
lua_gethookmask
int lua_gethookmask (lua_State *L);
返回当前的钩子掩码 (mask) 。 
________________________________________
lua_getinfo
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
返回一个指定的函数或函数调用的信息。 
当用于取得一次函数调用的信息时,参数 ar 必须是一个有效的活动的记录。这条记录可以是前一次调用 lua_getstack 得到的,或是一个钩子 (参见 lua_Hook)得到的参数。 
用于获取一个函数的信息时,可以把这个函数压入堆栈,然后把 what 字符串以字符 '>' 起头。(这个情况下,lua_getinfo 从栈顶上弹出函数。) 例如,想知道函数 f 在哪一行定义的,你可以下下列代码: 
     lua_Debug ar;
     lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* 取到全局变量 'f' */
     lua_getinfo(L, ">S", &ar);
     printf("%d/n", ar.linedefined);
what 字符串中的每个字符都筛选出结构 ar 结构中一些域用于填充,或是把一个值压入堆栈: 
?        'n': 填充 name 及 namewhat 域; 
?        'S': 填充 source, short_src, linedefined, lastlinedefined,以及 what 域; 
?        'l': 填充 currentline 域; 
?        'u': 填充 nups 域; 
?        'f': 把正在运行中指定级别处函数压入堆栈;(译注:一般用于获取函数调用中的信息,级别是由 ar 中的私有部分来提供。如果用于获取静态函数,那么就直接把指定函数重新压回堆栈,但这样做通常无甚意义。) 
?        'L': 压一个 table 入栈,这个 table 中的整数索引用于描述函数中哪些行是有效行。(有效行指有实际代码的行,即你可以置入断点的行。无效行包括空行和只有注释的行。) 
这个函数出错会返回 0 (例如,what 中有一个无效选项)。 
________________________________________
lua_getlocal
const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);
从给定活动记录中获取一个局部变量的信息。参数 ar 必须是一个有效的活动的记录。这条记录可以是前一次调用 lua_getstack 得到的,或是一个钩子 (参见 lua_Hook)得到的参数。索引 n 用于选择要检阅哪个局部变量( 1 表示第一个参数或是激活的第一个局部变量,以此类推,直到最后一个局部变量)。 lua_getlocal 把变量的值压入堆栈并返回它的名字。 
以 '(' (正小括号)开始的变量指内部变量(循环控制变量,临时变量,C 函数局部变量)。 
当索引大于局部变量的个数时,返回 NULL (什么也不压入)。 
________________________________________
lua_getstack
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
获取解释器的运行时栈的信息。 
这个函数用正在运行中的给定级别处的函数的活动记录来填写 lua_Debug 结构的一部分。 0 级表示当前运行的函数,而 n+1 级处的函数就是调用第 n 级函数的那一个。如果没有错误,lua_getstack 返回 1 ;当调用传入的级别大于堆栈深度的时候,返回 0 。 
________________________________________
lua_getupvalue
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
获取一个 closure 的 upvalue 信息。(对于 Lua 函数,upvalue 是函数需要使用的外部局部变量,因此这些变量被包含在 closure 中。) lua_getupvalue 获取第 n 个 upvalue ,把这个 upvalue 的值压入堆栈,并且返回它的名字。 funcindex 指向堆栈上 closure 的位置。( 因为 upvalue 在整个函数中都有效,所以它们没有特别的次序。因此,它们以字母次序来编号。) 
当索引号比 upvalue 数量大的时候,返回 NULL (而且不会压入任何东西)对于 C 函数,这个函数用空串 "" 表示所有 upvalue 的名字。 
________________________________________
lua_Hook
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
用于调试的钩子函数类型。 
无论何时钩子被调用,它的参数 ar 中的 event 域都被设为触发钩子的事件。 Lua 把这些事件定义为以下常量: LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILRET, LUA_HOOKLINE, and LUA_HOOKCOUNT。除此之外,对于 line 事件,currentline 域也被设置。要想获得 ar 中的其他域,钩子必须调用 lua_getinfo。对于返回事件,event 的正常值可能是 LUA_HOOKRET,或者是 LUA_HOOKTAILRET 。对于后一种情况,Lua 会对一个函数做的尾调用也模拟出一个返回事件出来;对于这个模拟的返回事件,调用 lua_getinfo 没有什么作用。 
当 Lua 运行在一个钩子内部时,它将屏蔽掉其它对钩子的调用。也就是说,如果一个钩子函数内再调回 Lua 来执行一个函数或是一个 chunk ,这个执行操作不会触发任何的钩子。 
________________________________________
lua_sethook
int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
设置一个调试用钩子函数。 
参数 f 是钩子函数。 mask 指定在哪些事件时会调用:它由下列一组位常量构成 LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE,以及 LUA_MASKCOUNT。参数 count 只在 mask 中包含有 LUA_MASKCOUNT 才有意义。对于每个事件,钩子被调用的情况解释如下: 
?        call hook: 在解释器调用一个函数时被调用。钩子将于 Lua 进入一个新函数后,函数获取参数前被调用。 
?        return hook: 在解释器从一个函数中返回时调用。钩子将于 Lua 离开函数之前的那一刻被调用。你无权访问被函数返回出去的那些值。 (译注:原文 (You have no access to the values to be returned by the function) 如此。但“无权访问”一词值得商榷。某些情况下你可以访问到一些被命名为 (*temporary) 的局部变量,那些索引被排在最后的 (*temporary) 变量指的就是返回值。但是由于 Lua 对特殊情况做了一些优化,比如直接返回一个被命名的局部变量,那么就找不到对应的 (*temporary) 变量了。本质上,返回值一定存在于此刻的局部变量中,并且可以访问它,只是无法确定是哪些罢了。至于这个时候函数体内的其它局部变量,是不保证有效的。进入 return hook 的那一刻起,实际已经退出函数内部的运行环节,返回值占用的局部变量空间以后的部分,都有可能因 hook 本身复用它们而改变。) 
?        line hook: 在解释器准备开始执行新的一行代码时,或是跳转到这行代码中时(即使在同一行内跳转)被调用。(这个事件仅仅在 Lua 执行一个 Lua 函数时发生。) 
?        count hook: 在解释器每执行 count 条指令后被调用。(这个事件仅仅在 Lua 执行一个 Lua 函数时发生。) 
钩子可以通过设置 mask 为零屏蔽。 
________________________________________
lua_setlocal
const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);
设置给定活动记录中的局部变量的值。参数 ar 与 n 和 lua_getlocal 中的一样(参见 lua_getlocal)。 lua_setlocal 把栈顶的值赋给变量然后返回变量的名字。它会将值从栈顶弹出。 
当索引大于局部变量的个数时,返回 NULL (什么也不弹出)。
///漏洞与补丁齐飞  蓝屏共死机一色


Step By Step(Lua-C API简介)

    2). Lua库中没有定义任何全局变量,而是将所有的状态都保存在动态结构lua_State中,后面所有的C API都需要该指针作为第一个参数。

    3). luaL_openlibs函数是用于打开Lua中的所有标准库,如io库、string库等。

    4). luaL_loadbuffer编译了buff中的Lua代码,如果没有错误,则返回0,同时将编译后的程序块压入虚拟栈中。
    5). lua_pcall函数会将程序块从栈中弹出,并在保护模式下运行该程序块。执行成功返回0,否则将错误信息压入栈中。
    6). lua_tostring函数中的-1,表示栈顶的索引值,栈底的索引值为1,以此类推。该函数将返回栈顶的错误信息,但是不会将其从栈中弹出。
    7). lua_pop是一个宏,用于从虚拟栈中弹出指定数量的元素,这里的1表示仅弹出栈顶的元素。
    8). lua_close用于释放状态指针所引用的资源。

    2. 栈:
在C/C++程序中,如果要获取Lua的值,只需调用Lua的C API函数,Lua就会将指定的值压入栈中。要将一个值传给Lua时,需要先将该值压入栈,然后调用Lua的C API,Lua就会获取该值并将其从栈中弹出。为了可以将不同类型的值压入栈,以及从栈中取出不同类型的值,Lua为每种类型均设定了一个特定函数。
    1). 压入元素:
    Lua针对每种C类型,都有一个C API函数与之对应,如:
    void lua_pushnil(lua_State* L);  --nil值
    void lua_pushboolean(lua_State* L, int b); --布尔值
    void lua_pushnumber(lua_State* L, lua_Number n); --浮点数
    void lua_pushinteger(lua_State* L, lua_Integer n);  --整型
    void lua_pushlstring(lua_State* L, const char* s, size_t len); --指定长度的内存数据
    void lua_pushstring(lua_State* L, const char* s);  --以零结尾的字符串,其长度可由strlen得出。
    在向栈中压入数据时,可以通过调用下面的函数判断是否有足够的栈空间可用,一般而言,Lua会预留20个槽位,对于普通应用来说已经足够了,除非是遇到有很多参数的函数。
    int lua_checkstack(lua_State* L, int extra) --期望得到extra数量的空闲槽位,如果不能扩展并获得,返回false。 
   
    2). 查询元素:
    API使用“索引”来引用栈中的元素,第一个压入栈的为1,第二个为2,依此类推。我们也可以使用负数作为索引值,其中-1表示为栈顶元素,-2为栈顶下面的元素,同样依此类推。
    Lua提供了一组特定的函数用于检查返回元素的类型,如:
    int lua_isboolean (lua_State *L, int index);
    int lua_iscfunction (lua_State *L, int index);
    int lua_isfunction (lua_State *L, int index);
    int lua_isnil (lua_State *L, int index);
    int lua_islightuserdata (lua_State *L, int index);
    int lua_isnumber (lua_State *L, int index);
    int lua_isstring (lua_State *L, int index);
    int lua_istable (lua_State *L, int index);
    int lua_isuserdata (lua_State *L, int index);
    Lua还提供了一个函数lua_type,用于获取元素的类型,函数原型如下:
    int lua_type (lua_State *L, int index);
    该函数的返回值为一组常量值,分别是:LUA_TNIL、LUA_TNUMBER、LUA_TBOOLEAN、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD和LUA_TLIGHTUSERDATA。这些常量通常用于switch语句中。
    除了上述函数之外,Lua还提供了一组转换函数,如:
    int lua_toboolean (lua_State *L, int index);
    lua_CFunction lua_tocfunction (lua_State *L, int index);
    lua_Integer lua_tointeger (lua_State *L, int index);    
    const char *lua_tolstring (lua_State *L, int index, size_t *len);
    lua_Number lua_tonumber (lua_State *L, int index);
    const void *lua_topointer (lua_State *L, int index);
    const char *lua_tostring (lua_State *L, int index);
    void *lua_touserdata (lua_State *L, int index);
    --string类型返回字符串长度,table类型返回操作符'#'等同的结果,userdata类型返回分配的内存块长度。
    size_t lua_objlen (lua_State *L, int index); 
    3). 其它栈操作函数:

    除了上面给出的数据交换函数之外,Lua的C API还提供了一组用于操作虚拟栈的普通函数,如:
    int lua_gettop(lua_State* L); --返回栈中元素的个数。

同时也是栈顶元素的索引,因为栈底是1,所以栈中有多少个元素,栈顶索引就是多少

    void lua_settop(lua_State* L, int index); --将栈顶设置为指定的索引值。

用于把堆栈的栈顶索引设置为指定的数值,比如说,一个栈原来有8个元素,调用函数设置index为7,就是把堆栈的元素数设置为7,也就是删掉一个元素,而且是栈顶元素;这个是用的正数,也就是相对于栈底元素设置的;如果是相对于栈顶元素,则要求用负值;也就是说如果设置索引为-2(index = -2),也相当于删除掉栈顶元素

    void lua_pushvalue(lua_State* L, int index); --将指定索引的元素副本压入栈。

    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶)有:
    lua_pushvalue(L, 3)    --> 10 20 30 40 50 30*
lua_pushvalue(L,3)是取得原来栈中的第三个元素,压到栈顶;
    void lua_remove(lua_State* L, int index); --删除指定索引上的元素,其上面的元素自动下移。

lua_remove删除给定索引的元素,并将这一索引之上的元素来填补空缺;下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:lua_remove(L, -3)      --> 10 20 40 50*

    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:

    lua_settop(L, -3)      --> 10 20 30 *

    lua_settop(L,  6)      --> 10 20 30 nil nil nil *

    void lua_insert(lua_State* L, int index); --将栈顶元素插入到该索引值指向的位置。
    void lua_replace(lua_State* L, int index); --弹出栈顶元素,并将该值设置到指定索引上。

    下面是一个例子,栈的初始状态为10 20 30 40 50 *(从栈底到栈顶,“*”标识为栈顶,有:
    lua_replace(L, 2)      --> 10 50 30 40 *    //把50替换到索引的位置,同时去掉栈顶元素


    Lua还提供了一个宏用于弹出指定数量的元素:#define lua_pop(L,n)  lua_settop(L, -(n) - 1)    
  

     下面是针对新函数的解释:

    lua_getglobal是宏,其原型为:#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, (s))
    每次调用这个宏的时候,都会将Lua代码中与之相应的全局变量值压入栈中,第一次调用时将全局变量"width"的值压入栈中,之后再次调用时再将"height"的值也压入栈中。

    2. table操作:
     void lua_getfield(lua_State *L, int idx, const char *k); 第二个参数是table变量在栈中的索引值,最后一个参数是table的键值,该函数执行成功后会将字段值压入栈中。

    void lua_setfield(lua_State *L, int idx, const char *k); 第二个参数是table变量在栈中的索引值,最后一个参数是table的键名称,而字段值是通过上一条命令lua_pushnumber(L,0.4)压入到栈中的,该函数在执行成功后会将刚刚压入的字段值弹出栈。
    
   

    lua_newtable是宏,其原型为:#define lua_newtable(L) lua_createtable(L, 0, 0)。调用该宏后,Lua会生成一个新的table对象并将其压入栈中。
    lua_setglobal是宏,其原型为:#define lua_setglobal(L,s) lua_setfield(L,LUA_GLOBALSINDEX,(s))。调用该宏后,Lua会将当前栈顶的值赋值给第二个参数指定的全局变量名。该宏在执行成功后,会将刚刚赋值的值从栈顶弹出。

    3. 调用Lua函数:
    调用函数的API也很简单。首先将待调用函数压入栈,再压入函数的参数,然后使用lua_pcall进行实际的调用,最后将调用结果从栈中弹出。




Step By Step(Lua调用C函数)

    Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性。对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数。对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L)。简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数。返回值是整型,表示该C函数将返回给Lua代码的返回值数量,如果没有返回值,则return 0即可。需要说明的是,C函数无法直接将真正的返回值返回给Lua代码,而是通过虚拟栈来传递Lua代码和C函数之间的调用参数和返回值的。这里我们将介绍两种Lua调用C函数的规则。
    1. C函数作为应用程序的一部分。

复制代码
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <lua.hpp>
 4 #include <lauxlib.h>
 5 #include <lualib.h>
 6 
 7 //待Lua调用的C注册函数。
 8 static int add2(lua_State* L)
 9 {
10     //检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
11     //如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
12     double op1 = luaL_checknumber(L,1);
13     double op2 = luaL_checknumber(L,2);
14     //将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
15     lua_pushnumber(L,op1 + op2);
16     //返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
17     return 1;
18 }
19 
20 //另一个待Lua调用的C注册函数。
21 static int sub2(lua_State* L)
22 {
23     double op1 = luaL_checknumber(L,1);
24     double op2 = luaL_checknumber(L,2);
25     lua_pushnumber(L,op1 - op2);
26     return 1;
27 }
28 
29 const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
30 
31 int main()
32 {
33     lua_State* L = luaL_newstate();
34     luaL_openlibs(L);
35     //将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码
36     //在调用C函数时使用的全局函数名,第二个参数为实际C函数的指针。
37     lua_register(L, "add2", add2);
38     lua_register(L, "sub2", sub2);
39     //在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
40     if (luaL_dostring(L,testfunc))
41         printf("Failed to invoke.\n");
42     lua_close(L);
43     return 0;
44 }
复制代码

    2. C函数库成为Lua的模块。
    将包含C函数的代码生成库文件,如Linux的so,或Windows的DLL,同时拷贝到Lua代码所在的当前目录,或者是LUA_CPATH环境变量所指向的目录,以便于Lua解析器可以正确定位到他们。在我当前的Windows系统中,我将其copy到"C:\Program Files\Lua\5.1\clibs\",这里包含了所有Lua可调用的C库。见如下C语言代码和关键性注释:

复制代码
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <lua.hpp>
 4 #include <lauxlib.h>
 5 #include <lualib.h>
 6 
 7 //待注册的C函数,该函数的声明形式在上面的例子中已经给出。
 8 //需要说明的是,该函数必须以C的形式被导出,因此extern "C"是必须的。
 9 //函数代码和上例相同,这里不再赘述。
10 extern "C" int add(lua_State* L) 
11 {
12     double op1 = luaL_checknumber(L,1);
13     double op2 = luaL_checknumber(L,2);
14     lua_pushnumber(L,op1 + op2);
15     return 1;
16 }
17 
18 extern "C" int sub(lua_State* L)
19 {
20     double op1 = luaL_checknumber(L,1);
21     double op2 = luaL_checknumber(L,2);
22     lua_pushnumber(L,op1 - op2);
23     return 1;
24 }
25 
26 //luaL_Reg结构体的第一个字段为字符串,在注册时用于通知Lua该函数的名字。
27 //第一个字段为C函数指针。
28 //结构体数组中的最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
29 static luaL_Reg mylibs[] = { 
30     {"add", add},
31     {"sub", sub},
32     {NULL, NULL} 
33 }; 
34 
35 //该C库的唯一入口函数。其函数签名等同于上面的注册函数。见如下几点说明:
36 //1. 我们可以将该函数简单的理解为模块的工厂函数。
37 //2. 其函数名必须为luaopen_xxx,其中xxx表示library名称。Lua代码require "xxx"需要与之对应。
38 //3. 在luaL_register的调用中,其第一个字符串参数为模块名"xxx",第二个参数为待注册函数的数组。
39 //4. 需要强调的是,所有需要用到"xxx"的代码,不论C还是Lua,都必须保持一致,这是Lua的约定,
40 //   否则将无法调用。
41 extern "C" __declspec(dllexport)
42 int luaopen_mytestlib(lua_State* L) 
43 {
44     const char* libName = "mytestlib";
45     luaL_register(L,libName,mylibs);
46     return 1;
47 }
复制代码

    见如下Lua代码:

1 require "mytestlib"  --指定包名称
2 
3 --在调用时,必须是package.function
4 print(mytestlib.add(1.0,2.0))
5 print(mytestlib.sub(20.1,19))

简明lua教程

自己整理的lua快速自学文档,供参考。

 

---------------list start------------------
【LUA基本语法】
【LUA常用函数】
【技巧集】
【API reference】
【参考资料】
---------------list end--------------------

 

【LUA基本语法】
1.1 全局变量不需要声明
   b = nil
   删除一个全局变量 
   print(b) --> nil

1.2 退出LUA的方法
  Ctrl-D(linux) Ctrl-Z(DOS/Windows) 调用OS库的函数 os.exit()

1.3 执行lua的chunk方法
   执行一系列:lua -l<filename> -l<filename>
   在交互模式下调用dofile函数 >dofile("<filename>")

1.4 注释
注意:Lua是大小写敏感的.
注释:单行注释:--
多行注释:--[[ --]]

1.5条件判断
在控制结构的条件中除了false和nil为假,其他值都为真。所以Lua认为0和空串都是真。

对于Table,Function和Userdata类型的数据,只有 == 和 ~=可以用。相等表示两个变量
引用的是同一个数据。比如:
    a={1,2}
    b=a
    print(a==b, a~=b) -- true, false
    a={1,2}
    b={1,2}
    print(a==b, a~=b) -- false, true

1.6 连接运算符
print(10 .. 12)   --> 1012

1.7 逻辑运算符
逻辑运算符认为false和nil是假(false),其他为真,0也是true.
and的优先级比or高。
a and b -- 如果a为false,则返回a,否则返回b
a or b -- 如果a为true,则返回a,否则返回b
如果x为false或者nil则给x赋初始值v
x = x or v
C语言中的三元运算符
a ? b : c
(a and b) or c

1.8 引用表中成员
w = {x=0, y=0, label="console"}
print(w.x)       --> 0
print(w["x"])    --> 0

1.9 迭代器
function list_iter (t)
    local i = 0
    local n = table.getn(t)
    return function ()
                i = i + 1
                if i <= n then return t[i] end
            end
end

t = {10, 20, 30}
for element in list_iter(t) do
print(element)
end

1.10 for循环
- 第一种:数值循环
for var=exp1,exp2,exp3 do
    loop-part
end
for将用exp3作为step从exp1(初始值)到exp2(终止值),执行loop-part。
其中exp3可以省略,默认step=1
- 第二种:范性for
for <var-list> in <exp-list> do
    <body>
end
<var-list>是一个或多个以逗号分割的变量名列表,<exp-list>是一个或多
个以逗号分割的表达式列表,通常情况下exp-list只有一个值:迭代工厂的调用。
变量列表中第一个变量为控制变量,其值为nil时循环结束。
表达式应该返回范性for需要的三个值:迭代函数,状态常量和控制变量;
表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略;
将状态常量和控制变量作为参数调用迭代函数;
迭代函数返回的值赋给变量列表。

1.11 错误处理
error函数抛出异常
assert调用抛出异常
pcall函数调用

1.12 协同程序
coroutine.create(<协同程序名,一般为匿名函数>)
coroutine.resume(<create返回的协同程序名>,[传给协同程序的参数列表])
resume函数的返回值除了true或false以外,还有yield的所有参数

1.13 __le和__lt __eq
一般实现__le后,还要实现__lt 和__eq
Set.mt.__lt = function (a,b)
 return a <= b and not (b <= a)
end
Set.mt.__eq = function (a,b)
 return a <= b and b <= a
end

1.14 有默认值的表实现(所有表共享同一个metatable)
local key = {} -- unique key
local mt = {__index = function(t) return t[key] end}
function setDefault (t, d)
    t[key] = d
    setmetatable(t, mt)
end
-->上面的写法,每一个表占用一个空间存储默认值d
tab = {x=10, y=20}
print(tab.x, tab.z) --> 10 nil
setDefault(tab, 0)
print(tab.x, tab.z) --> 10 0

1.15 只读的表实现
每一个只读代理有一个单独的新的metatable,使用__index指向原始表

1.16 监控表的实现
设置一个空表,这样就会总能触发__index和__newindex

1.17 LUA全局变量
枚举所有全局变量
  for n in pairs(_G) do print(n) end
打印制定全局变量,例如:
print(_G["loadfile"])

1.18 __index metamethod     P108
__index metamethod不需要非是一个函数,他也可以是一个表。
但它是一个函数的时候,Lua将table和缺少的域作为参数调用这个函数;
当他是一个表的时候,Lua将在这个表中看是否有缺少的域。
1.19 包 module
http://blog.csdn.net/chenyufei1013/archive/2009/08/12/4438801.aspx
module 指令运行完后,整个环境被压栈,所以前面全局的东西再看不见了。
local print=print
module("test")
print(...)
或者
local _G=_G
module("test")
_G.print(...)
或者
module("test",package.seeall)
print(...)

1.20 C API
 
#define lua_open() luaL_newstate()

lua_State *L = lua_open();
lua_open()
luaL_newstate()

luaL_openlibs

luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);


空值(nil)用lua_pushnil
数值型(double)用lua_pushnumber
布尔型(在C中用整数表示)用lua_pushboolean
任意的字符串(char*类型,允许包含'\0'字符)用lua_pushlstring
C语言风格(以'\0'结束)的字符串(const char*)用lua_pushstring

lua_tostring(L, -1)  以字符串的形式返回栈顶的值
API提供了一套lua_is*函数来检查一个元素是否是一个指定的类型
lua_getglobal(L, <global name>) 获得lua文件中的变量并压入栈中
<global name>一般为module名或者table名

lua_gettable(L, <table在堆栈中的索引>)
用lua_gettable取出table中的元素并压入栈中。
例如:
  lua_getglobal(L, "background"); //将表压栈
  lua_pushstring(L, "red") //首先将key压栈
  lua_gettable(L, -2);  --> get background["red"]

一种简便的方法如下:直接使用lua_getfield
lua_getfield(L, <global index>, <field name>)
<global index>为<field name>相对应的global索引,global可能是上次

lua_pop(L, <弹出栈元素个数>)

在调用脚本之前可以在C语言中设置global变量或者table对象
然后在脚本中就可以执行C语言中设置的变量或对象了。
lua_pushstring
lua_newtable(L)
lua_setfield(L, <table index>, <field name>) //栈顶必须是要设置的<field value>
lua_setglobal(L, <要设置的全局名称>)  //栈顶必须有要设置的元素
例如:
lua_pushnumber(L, ct1.red/MAX_COLOR);
lua_setfield(L, -2, "r");
lua_pushnumber(L, ct1.green/MAX_COLOR);
lua_setfield(L, -2, "g");
lua_setglobal(L, "RED");
LUA调用C文件中的函数方法:
 需要注册函数
lua_pushcfunction(l, l_sin);
lua_setglobal(l, "mysin");


C调用LUA文件中的函数方法:
lua_getglobal(L, <function name>)
lua_push*() //例如lua_pushnumber(L, x)
lua_pcall(L, <arguments nums>, <return nums>, <错误处理函数地址>)
例如lua_pcall(L, 2, 1, 0)
//获得返回值
lua_to*() //例如lua_tonumber(L, -1);
lua_pop(L,1)

C作为库文件被Lua调用,C文件统一接口函数
luaopen_<dll name>, <dll name>必须和dll保持一致
例如:
#define _EXPORT extern "C" __declspec(dllexport)
_EXPORT int luaopen_capi_mytestlib(lua_State *L)
{
    struct luaL_reg driver[] = {
        {"average", average1},
        {NULL, NULL},};
    luaL_register(L, "mylib", driver);
    //luaL_openlib(L, "mylib", driver, 0);
    return 1;
}
li情况
按照网上所说,LUA加载C动态库搞了一把,终于在LINUX下搞通了,白白浪费许多时间。
总结几条:
1.动态库要供LUA调用的function,其定义要符合:
typedef int function(lua_State *L)
这个一般大家都知道

2.在动态库调用LUA注册:
将要调用的函数放到这个结构体里:
struct luaL_Reg lib[] =
{}
在动态库的入口函数里调用luaL_register将这个结构体注册

3.入口函数定义很重要,一定是要定义成:
int luaopen_XXX(lua_State *L)
否则就提示找不到动态库,

在这个入口函数注册结构体时,要注册成:
luaL_register(L,"XXX",lib);
与入口函数的luaopen_XXX的XXX要一致。

4.在写脚本的时候,使用require("XXX"),就是入口函数的luaopen_后面的XXX,注意大小写敏感

5.编译生成的动态库命令成XXX.so,对,同入口函数的luaopen_后面的XXX一致

SAMPLE:

C文件如下:
#include <stdio.h>
#include "lua/lua.h"
#include "lua/lualib.h"
#include "lua/lauxlib.h"
static int add(lua_State *L)
{
int a,b,c;
a = lua_tonumber(L,1);
b = lua_tonumber(L,2);
c = a+b;
lua_pushnumber(L,c);
printf("test hello!!!\r\n");
return 1;
}
static const struct luaL_Reg lib[] =
{
{"testadd",add},
{NULL,NULL}
};
int luaopen_testlib(lua_State *L)
{
luaL_register(L,"testlib",lib);
return 1;
}


编译: gcc  test.c -fPIC -shared -o testlib.so


脚本编写:
 
require("testlib")
c = testlib.testadd(15,25)
print("The result is ",c);


1.21 字符串面值
http://hi.baidu.com/duyingjie/blog/item/e3b027347804cf3e5ab5f55b.html

1.22 面向对象
1) 对象 类
setmetatable(a, {__index = b})
a相当于对象,b相当于类;对象a调用任何不存在的成员都会到对象b中查找
一个类的简单实现:
local _G =  _G;
module "packparse"
function New(self,o)
 _G.setmetatable(o,self);
 self.__index = self;
 return o;
end

http://apps.hi.baidu.com/share/detail/19659260
http://www.cnblogs.com/simonw/archive/2007/01/17/622032.html
导入C++中对象到lua中
http://hi.baidu.com/wndex/blog/item/62f86e20c9f750429358073a.html

1.23 userdata用途
在Lua中自定义类型,该类型由C函数操作。Lua为这种情况提供专门提供一个基本的类型:
userdata。一个userdatum提供了一个在Lua中没有预定义操作的raw内存区域。

每次我们访问数组的时候,我们都要检查他是否有一个正确的metatable。
因为Lua代码不能改变userdatum的metatable,所以他不会伪造我们的代码。

 

【LUA常用函数】
2.1 type函数,测试给定变量或者值的类型
2.2 字符串处理函数 字符串与数值转换函数
  替换函数, string.gsub(a, "one", "another")
  字符串 数字间转换函数 tonumber tostring

2.3 io读写函数
    io.read  io.write
    io.open打开文件??
2.4 遍历for循环函数pairs ipairs
pairs能遍历所有的元素,ipairs只能遍历数组
--for i in pairs(days) do
-- print(days[i])
--end  
--for i,value in pairs(days) do
-- print(value)
--end
ipairs使用key的顺序1、2、pairs使用表的自然存储顺序。
2.5 table表处理函数
  table.getn(<table variable name>)
2.6 string字符串处理函数
 前缀 后缀
string.sub(s, 1, j)返回字符串s的长度为j的前缀;
string.sub(s, j, -1)返回从第j个字符开始的后缀;
string.char将数字转换成整数
string.byte将字符串制定位置的字符转换成整数
字符串部分替换string.gsub(目标串,模式串,替换串,替换次数)
例如:计算空格出现次数 _, count = string.gsub(str, " ", " ")
string.sub(s,i,j)函数截取字符串s的从第i个字符到第j个字符之间的串
string.find(目标串,要查找串)
例如:
s = "Deadline is 30/05/1999, firm"
date = "%d%d/%d%d/%d%d%d%d"
print(string.sub(s, string.find(s, date))) --> 30/05/1999
gsub进行子串替换
s = "\\command{some text}"
print(s)
s = string.gsub(s, "\\(%a+){(.-)}", "<%1>%2</%1>")
print(s)
--> <command>some text</command>

2.7 模式匹配
 *和-区别
‘*’进行最长匹配
test = "int x; int y; "
print(string.gsub(test, "/%*.*%*/", "<COMMENT>"))
--> int x; <COMMENT>
‘-’进行最短匹配
test = "int x; int y; "
print(string.gsub(test, "/%*.-%*/", "<COMMENT>"))
--> int x; <COMMENT> int y; <COMMENT>
  匹配位置定位 ^ $
  string.find(s, "^[+-]?%d+$")  -- 检查字符串s是否以数字开头
  string.find(s, "^%d") -- 检查字符串s是否以数字开头
'%b' 用来匹配对称的字符 常用的这种模式有:'%b()' ,'%b[]','%b%{%}' 和 '%b<>'
2.8 模式捕获
pair = "name = Anna"
_, _, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)")
print(key, value) --> name Anna
2.9 require函数

2.10 产生随机数
math.random(0,1); 产生随机整数0~1


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
【技巧集】
X. 数组里面的元素可以是函数

Q: lua_pushliteral和lua_pushstring有何区别?
A: 通常在push字符串字面值时使用lua_pushliteral,在push字符串指针是使用lua_pushstring。
   原因是前者通过sizeof(字符串字面值)/sizeof(char)计算长度,而后者通过strlen计算长度。
   因此前者只能push字符串字面值,但速度比后者快。而后者既可push字符串字面值,也可push字符串指针。

Q: luaL_loadfile, luaL_loadstring, luaL_loadbuffer的区别?
A: luaL_loadfile把文件内容作为chunk,并在内部调用lua_load
    luaL_loadstring把字符串栈转为buffer调用luaL_loadbuffer
   luaL_loadbuffer把buffer的内容作为chunk,并在内部调用lua_load
   lua_load则将chunk作为lua function压栈,并具有自动分析chunk是二进制(luac)还是普通文本的能力

Q: lua_pcall, lua_resume的区别?
A: lua_resume只可以用在coroutine中,当coroutine没有任何yield时,lua_resume可以用lua_pcall代替


LUA的优点:
昨天你问为什么要用LUA解析报文,因为用C++解析报文,当报文的内容更改,C++代码也要作修改,
要重新编译,服务器要重新启动,但是在LUA中处理解析的话,可以热更新。LUA也可以做配置,当
然可以采用xml,但用就用一种,方便管理。用脚本也就是为了应付灵活多变的需求,我们是做游戏,
需求经常变动。比如要增加一个新功能,直接用LUA写下,做个客户端管理工具,给他发个包,让他
加载下指定的LUA文件,服务器在不重启的情况下,就能提供新的功能了,给用户的体验很好,不会
动不动停机维护

LUA编译环境:
C/C++ -> 代码生成 -> 多线程调试(/MT /MTd)
头文件要 extern "C"
extern "C" {
#include "./lua/lua.h"
#include "./lua/lauxlib.h"
#include "./lua/lualib.h"
};

 

调用类中方法
int ret = luaL_dofile(m_pLua,filepath.c_str());
if(ret!=0) {
 。。。
}
lua_getglobal(m_pLua,"globlePath");
lua_getfield(m_pLua,-1,"SetPath");
ret = lua_pcall(m_pLua,1,0,0);
lua_settop(m_pLua,0);

获得lua文件中的全局变量
int ret = luaL_dofile(m_pLua,filepath.c_str());
if(ret!=0) {
 。。。
}
lua_getglobal(m_pLua,"selfPort");
m_port = lua_tointeger(m_pLua,-1);或者m_ManageSvr.strIp = lua_tostring(m_pLua,-1);
lua_pop(m_pLua,1);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
【API reference】
X. lua_pushnumber
void lua_pushnumber (lua_State *L, lua_Number n);
Pushes a number with value n onto the stack.

X. lua_setfield
void lua_setfield (lua_State *L, int index, const char *k);
Does the equivalent to t[k] = v, where t is the value at the given valid index index and v is the
value at the top of the stack, This function pops the value from the stack. As in Lua, this function
may trigger a metamethod for the "newindex" event.

X. lua_getfield
Pushes onto the stack the value t[k], where t is the value at the given valid index index. As in Lua, this
function may trigger a metamethod for the "index" event


1. luaL_dofile
int luaL_dofile (lua_State *L, const char *filename);
Loads and runs the given file. It is defined as the following macro:

2. lua_getglobal
void lua_getglobal (lua_State *L, const char *name);
Pushes onto the stack the value of the global name. It is defined as a macro

 

4. lua_pushstring
Pushes the zero-terminated string pointed to by s onto the stack. Lua makes (or reuses) an internal copy of the

given string, so the memory at s can be freed or
reused immediately after the function returns. The string cannot contain embedded zeros; it is assumed to end at

the first zero.

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

Calls a function in protected mode.
Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call,
lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, pushes
a single value on the stack (the error message), and returns an error code. Like lua_call, lua_pcall
always removes the function and its arguments from the stack.

6. lua_settop
void lua_settop (lua_State *L, int index);

Accepts any acceptable index, or 0, and sets the stack top to this index.
If the new top is larger than the old one, then the new elements are filled with nil. If index is 0, then all stack

elements are removed.

7. 压入参数
lua_pushnumber
lua_pushstring

8. lua_pop
void lua_pop (lua_State *L, int n);
Pops n elements from the stack.

9. lua_pushcfunction
Pushes a C function onto the stack. This function receives a pointer to a C function and pushes onto
the stack a Lua value of type function that, when called, invokes the corresponding C function.

10. lua_setglobal
void lua_setglobal (lua_State *L, const char *name);
Pops a value from the stack and sets it as the new value of global name. It is defined as a macro:

11. lua_isuserdata
Returns 1 if the value at the given acceptable index is a userdata (either full or light),
and 0 otherwise.

12. lua_touserdata
void *lua_touserdata (lua_State *L, int index);

If the value at the given acceptable index is a full userdata, returns its block address.
If the value is a light userdata, returns its pointer. Otherwise, returns NULL.


13.,luaL_checkudata
检查在栈中指定位置的对象是否为带有给定名字的metatable的usertatum。如果对象不存在正确的metatable,
返回NULL(或者它不是一个userdata);否则,返回userdata的地址。

14. luaL_newmetatable
int luaL_newmetatable (lua_State *L, const char *tname);
把表存入注册表
If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used
 as a metatable for userdata, adds it to the registry with key tname, and returns 1.

15. lua_settop
lua_settop设置栈顶(也就是堆栈中的元素个数)为一个指定的值。如果开始的栈顶高于新的栈顶,
顶部的值被丢弃。否则,为了得到指定的大小这个函数压入相应个数的空值(nil)到栈上。
特别的,lua_settop(L,0)清空堆栈。

【参考资料】
正则表达式
http://blog.csdn.net/liuyukuan/archive/2010/04/15/5489623.aspx
Lua数据结构
http://blog.csdn.net/HowdyHappy/archive/2010/10/30/5976676.aspx
闭包
http://hi.baidu.com/happynp/blog/item/b7736a1f7f65b3ffe0fe0b90.html
lua和C集成调试
http://sailtsao.spaces.live.com/blog/
官网
http://www.lua.org/download.html
电子教学书EBOOK
Programming in LUA
http://www.inf.puc-rio.br/~roberto/book/
http://www.lua.org/pil/
Lua Programming Gems
http://www.lua.org/gems/
Premier Press Game Programming with Python Lua and Ruby
Game development with lua
lua源码分析
http://www.javaeye.com/topic/520300
http://blog.csdn.net/INmouse/archive/2007/03/25/1540418.aspx
lua编辑器
http://www.gorlice.net.pl/~rybak/luaide/
http://sourceforge.net/projects/luaedit/
http://luaforge.net/projects/luaedit/
LUA 5.1参考手册
 英文版本
http://www.lua.org/manual/5.1/manual.html
http://manual.luaer.cn/   
 中文版本
http://www.codingnow.com/2000/download/lua_manual.html
http://blog.csdn.net/mephp/archive/2009/10/29/4743086.aspx
 迷你lua 5.1参考手册
http://blog.csdn.net/skyremember/archive/2008/09/10/2908718.aspx
LUASOCKET 参考手册
http://www.tecgraf.puc-rio.br/~diego/professional/luasocket/introduction.html
C/C++中调用LUA函数
http://blog.csdn.net/skyremember/archive/2008/09/19/2951709.aspx
lua调用C/C++ 函数
http://blog.163.com/jinpengxuan@126/blog/static/554107892009631263478/
Lua调用C++类
注册C函数与类成员函数到lua
http://blog.csdn.net/siddontang/archive/2008/04/20/2309381.aspx
LUA模式匹配
http://www.cnblogs.com/whiteyun/archive/2009/09/02/1541043.html
http://www.d7game.cn/bencandy.php?fid-254-id-53-page-1.htm
LUA实现单链表
http://hi.baidu.com/microsoftxiao/blog/item/2bae74609de94142eaf8f808.html
LUA配置:
LUA_PATH=< LDIR>/?.lua;?.lua
LUA_CPATH=<CDIR>/?.dll;?.dll
加密解密lua脚本
http://blog.codingnow.com/2007/04/user_define_lua_loader.html
http://lua-users.org/lists/lua-l/2007-06/msg00335.html
第三方开发库
MD5
http://www.keplerproject.org/md5/manual.html


http://ouonline.net/programming-in-lua-6


lua是一个嵌入式语言,就是说它不是一个单独的程序,而是一套可以在其它语言中使用的库,在前面使用过的lua交互程序其实是利用lua提供的库所实现的一个解析器。lua可以作为c语言的扩展,反过来也可以用c语言编写模块来扩展lua,这两种情况都使用同样的api进行交互。lua与c主要是通过一个虚拟的“栈”来交换数据。


因为lua.h中没有使用”extern C”来为c++导出函数接口,因此如果要在c++中使用lua,include的时候使用lua.hpp而不是lua.h。

头文件lua.h中定义了lua提供的基本函数,包括创建环境,读写变量,注册函数等,这些函数都以”lua_”为前缀。lauxlib.h定义了一些辅助函数,这些函数使用了lua.h中提供的基本功来来提供一些更高层次的功能,它们都以”luaL_”作为前缀。lua函数并没有定义全局变量,所有的变量都在lua_State中,lua的函数都是可重入的。

在c语言中使用函数

lua_State *luaL_newstate (void);

创建一个新的lua执行环境。这个环境里什么都没有,因此需要使用函数

void luaL_openlibs (lua_State *L);

加载所有的标准库。之后可以使用

int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);

加载并解析读到的内容。最后的参数name是调试的时候输出错误信息用的。如果解析成功,luaL_loadbuffer()会把结果压到“栈”里。然后就使用函数

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

在lua保护模式下运行语句。如果运行出错,函数会把错误信息压到“栈”里。我们可以通过

const char *lua_tostring (lua_State *L, int index);

来获取错误信息。在调用函数前,用户应该先把语句所需的参数都压到栈里,参数nargs说明有多少个参数,nresults表示返回值有多少个。如果msgh值为0表示“栈”里返回的是原始的错误信息。

在函数执行完后,lua会把函数以及其使用的参数从栈里删掉,并且把结果压入栈里。lua函数并不会打印任何信息,它只会返回一个错误代码,然后由调用者对错误进行适当的处理。

最后把错误信息弹出:

void lua_pop (lua_State *L, int n);

参数n表示要弹出元素的个数。

最后使用

void lua_close (lua_State *L);

释放所有的资源。

“栈”的基本操作

在lua和c之间交换数据面临两个难题:一个是动态类型和静态类型的区别,一个是动态内存管理和人工内存管理的区别。例如在lua中的语句”a[k]=v”,其中a,k,v都可能有不同的类型。在c语言中我们可以定义一个联合lua_value,但是对于其它语言来说却没有这样的数据类型,而且lua无法得知在c语言中使用的变量是不是动态分配的,因此可能会错误地回收变量所占的资源。因此lua使用一个栈来和其它语言交换数据。lua把数据压栈,其它语言从栈里弹出数据;或者其它语言把数据压到栈里,lua从其中获取数据。几乎所有的lua函数都使用这个栈来与其它语言进行数据交换。

lua为c语言提供了一系列函数来把lua中不同类型的数据压到栈里:

void lua_pushnil     (lua_State *L);                                /* nil */
void lua_pushboolean (lua_State *L, int bool);                      /* bool */
void lua_pushnumber  (lua_State *L, lua_Number n);                  /* double by default */
void lua_pushinteger (lua_State *L, lua_Integer n);                 /* int */
void lua_pushlstring (lua_State *L, const char *s, size_t len);     /* s and len */
void lua_pushstring  (lua_State *L, const char *s);                 /* null-terminated string */

lua_Number默认是double类型的,但是在某些平台上可能是float或者long。lua中的字符串并不是以”\0″作为结束标志,因此通常还需要一个表示长度的域。lua会复制一份压到栈里的内容,因此可以在这些函数外释放参数的资源(例如动态分配的内存)。

在把参数压到栈里之前需要检查栈里是否还有足够的空间:

int lua_checkstack (lua_State *L, int expected);

lua会自动扩充栈的大小为expected,如果扩容失败或超出限制则返回错误编号。如果栈足够大,lua并不会缩小栈的大小。

api中使用索引来获取栈的内容。以栈底为参考点,第一个压进栈里的元素的索引为1,第二个为2,以此类推。除此之外还可以以栈顶为参考点,那么栈顶的元素索引为-1,前一个元素索引为-2,等等。在上面的例子里,lua_tostring(l, -1)就是获取栈顶的内容并且把它转换成一个字符串。

lua还提供了一些函数来检查栈的某个位置的元素的类型。例如lua_isnumber(),lua_isstring(),lua_istable()等。这些函数都有一个相似的函数原型:

int lua_is* (lua_State *L, int index);

事实上lua并不是检查该位置的元素是否就是对应的类型,而是判断该元素能否转换成对应的类型,例如lua_isstring()对于任何数值都会返回真值,也就是说数字可以转换成对应的字符串。

另外还有一个函数

int lua_type (lua_State *L, int index);

用来判断某个位置的元素类型(类型定义在lua.h中),这在switch语句中很方便,也避免了字符和数值之间的相互转换。

下面的函数用来从“栈”里取出数据:

int         lua_toboolean (lua_State *L, int index);
lua_Number  lua_tonumber  (lua_State *L, int index);
lua_Integer lua_tointeger (lua_State *L, int index);
const char *lua_tolstring (lua_State *L, int index, size_t *len);
size_t      lua_objlen    (lua_State *L, int index);

这里并不要求index指向的元素就是所需的类型。如果index指向的元素不能转换成所需的类型,函数会返回0或NULL,因此转换前不需要判断类型,而可以通过lua_to*系列函数的返回值来判断是否转换成功。

lua_tolstring()的返回值指向的是lua内部的字符串,字符串的长度放在第三个参数len中。如果需要保存字符串的内容需要用memcpy()之类的函数复制一份,因为lua会把“栈”的内容给清空。(没搞清楚什么时候清空,原文是:When a C function called by Lua returns, Lua clears its stack;)

lua_tolstring()返回的字符串最后都有一个’\0′,因为不能确定字符串中间有没有’\0′,所以返回值的真实长度要看len的值。如果不需要长度值,len可以为NULL,或者直接使用

const char *lua_tostring (lua_State *L, int index);

lua_objlen()获取一个object的长度,这个object可以是字符串,表或用户自定义的数据。如果是字符串和表,函数的返回值和取长度的操作符”#”结果是一样的。

“栈”的其它操作

下面是其它的一些操作函数:

int  lua_gettop    (lua_State *L);
void lua_settop    (lua_State *L, int index);
void lua_pushvalue (lua_State *L, int index);
void lua_remove    (lua_State *L, int index);
void lua_insert    (lua_State *L, int index);
void lua_replace   (lua_State *L, int index);

lua_gettop()返回“栈”顶元素相对于“栈”底的索引(也即“栈”里的元素个数)。lua_settop()改变“栈”的大小:如果原来的大小比index大,则位于index上的元素都被删除;如果原来的大小比index小,则往“栈”里填充nil。特别地,lua_settop(l, 0)清空整个“栈”。index也可以为负数(即以“栈”顶为基准),因此下面的宏

#define lua_pop(L,n) lua_settop(L, -(n) - 1)

用来从“栈”里弹出n个元素。

lua_pushvalue()把位于index的元素复制一份,然后将其放入“栈”顶;lua_remove()删除位于index的元素,并且将index之上的元素依次往下移;lua_insert()将“栈”顶的元素移到位置index,并且将原来index及其以上的元素依次往上移;lua_replace()将位于index的值修改为“栈”顶元素的值,并且将“栈”顶元素删除。




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值