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
2 #include <string .h>
3 #include
4 #include
5 #include
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
2 #include <string .h>
3 #include
4 #include
5 #include
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 -l 在交互模式下调用dofile函数 >dofile("")
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 in do end 是一个或多个以逗号分割的变量名列表,是一个或多 个以逗号分割的表达式列表,通常情况下exp-list只有一个值:迭代工厂的调用。 变量列表中第一个变量为控制变量,其值为nil时循环结束。 表达式应该返回范性for需要的三个值:迭代函数,状态常量和控制变量; 表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略; 将状态常量和控制变量作为参数调用迭代函数; 迭代函数返回的值赋给变量列表。
1.11 错误处理 error函数抛出异常 assert调用抛出异常 pcall函数调用
1.12 协同程序 coroutine.create(<协同程序名,一般为匿名函数>) coroutine.resume(,[传给协同程序的参数列表]) 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, ) 获得lua文件中的变量并压入栈中 一般为module名或者table名
lua_gettable(L,
) 用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索引,global可能是上次
lua_pop(L, <弹出栈元素个数>)
在调用脚本之前可以在C语言中设置global变量或者table对象 然后在脚本中就可以执行C语言中设置的变量或对象了。 lua_pushstring lua_newtable(L) lua_setfield(L,
, ) //栈顶必须是要设置的 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, ) lua_push*() //例如lua_pushnumber(L, x) lua_pcall(L, , , <错误处理函数地址>) 例如lua_pcall(L, 2, 1, 0) //获得返回值 lua_to*() //例如lua_tonumber(L, -1); lua_pop(L,1)
C作为库文件被Lua调用,C文件统一接口函数 luaopen_, 必须和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 #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(
) 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) --> some text
2.7 模式匹配 *和-区别 ‘*’进行最长匹配 test = "int x; int y; " print(string.gsub(test, "/%*.*%*/", "")) --> int x; ‘-’进行最短匹配 test = "int x; int y; " print(string.gsub(test, "/%*.-%*/", "")) --> int x; int y; 匹配位置定位 ^ $ 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=/?.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的值修改为“栈”顶元素的值,并且将“栈”顶元素删除。
你可能感兴趣的:(lua)
spring security中几大组件的作用和执行顺序
阿信在这里
java spring
springsecurity中几大组件的作用和执行顺序在SpringSecurity中,AuthenticationProvider、GroupPermissionEvaluator、PermissionEvaluator、AbstractAuthenticationProcessingFilter、DefaultMethodSecurityExpressionHandler和ManageSecu
Lua 与 C#交互
z2014z
lua c# 开发语言
Lua与C#交互前提Lua是一种嵌入式脚本语言,Lua的解释器是用C编写的,因此可以方便的与C/C++进行相互调用。轻量级Lua语言的官方版本只包括一个精简的核心和最基本的库,这使得Lua体积小、启动速度快,也适合嵌入在别的程序里。交互过程C#调用Lua:由C#文件调用Lua解析器底层dll库(由C语言编写),再由dll文件执行相应的Lua文件。Lua调用C#:1、Wrap方式:首先生成C#源文件
基于Python执行lua脚本
xu-jssy
Python自动化脚本 python lua 自动化 rpa
一、依赖安装pipinstalllupa二、源码将lua文件存放在base_path路径,将lua文件名称(不包含后缀名)传递给lua_runner函数即可importmultiprocessingimportlupa#lua文件存放位置base_path='D:\\test\\lua'classLuaFuncion:#创建Lua运行时环境lua=lupa.LuaRuntime(unpack_re
GO Govaluate
qq_17280559
golang 开发语言 后端 go
govaluate是一个用于在Go语言中动态求值表达式的库。它允许你解析和评估字符串形式的表达式,这些表达式可以包含变量、函数以及逻辑、算术和比较操作。它非常适合在运行时处理复杂的逻辑规则和条件表达式,而不需要重新编译代码。安装govaluategogetgithub.com/Knetic/govaluate基本使用govaluate的核心是Evaluate方法,它接受表达式字符串和变量值,并返回
Cocos2d、Cocos2dx、Cocos Creator、Cocos Studio的区别
Thomas游戏圈
一、Cocos2d和Cocos2dx的区别【开发语言】:Cocos2d是Object-C写的,Cocos2dx是C++写的,支持使用C++、Lua或Java进行开发。【运行平台】:Cocos2d只能在IOS下运行,Cocos2dx是跨平台的,适配iOS、Android、HTML5、Windows和Mac系统,功能侧重于原生移动平台。点击链接加入群聊【Unity/Cocos交流群】【国籍】:Coco
模糊综合评价法 (评价类问题)
NON-JUDGMENTAL
数学建模-模型汇总 大数据 matlab 数学建模 算法
一.概念模糊综合评价法(FuzzyComprehensiveEvaluation,FCE)是一种将模糊数学与综合评价相结合的方法,常用于处理那些涉及多因素、多指标的复杂评价问题,特别是在处理含有模糊性、主观性的评价问题时。模糊数学模糊是指客观事物差异的中间过渡中的“不分明性”或“亦此亦彼性”。如高个子与矮个子、年轻人与老年人、热水与凉水、环境污染严重与不严重等。在决策中,也有这种模糊的现象,如选举
遗传算法(Genetic Algorithm,GA)-基于MATLAB环境实现
朱佩棋(代码版)
启发式算法 启发式算法 算法 matlab
1.GA简介geneticalgorithm,美国Holland教授创立,基于达尔文进化论和孟德尔的遗传学说。遗传算法类比了生物界中自然选择、交叉、变异等自然进化方式,利用数码串类比染色体,通过选择、交叉、变异等遗传算子模拟生物的进化过程。1.1遗传算法的流程1.编码伪代码:2.产生初始群体Chooseinitialpopulation3.计算适应度Evaluatethefitnessofeach
Lua协同程序Coroutine
z2014z
lua 开发语言
Lua协同程序(Coroutine)定义Lua协同程序(Coroutine)与线程类似:拥有独立的堆栈、局部变量、指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。协同程序可以理解为一种特殊的线程,可以暂停和恢复其执行,从而允许非抢占式的多任务处理。协同是非常强大的功能,但是用起来也很复杂。线程和协同程序区别主要区别在于,一个程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。在任
浅谈lua拷贝
coding·life
Lua初探 lua拷贝 深拷贝
lua中对象的拷贝分为2种:浅拷贝(ShallowCopy)和深拷贝(DeepCopy)。浅拷贝简单来说只是对一些基本的类型进行复制,而像table这样的类型则直接引用。目前对于浅拷贝有2种说法:1.赋值操作符"="即是浅拷贝2.使用代码实现浅拷贝,代码如下:functionshallow_copy(object)localnewObjectiftype(object)=="table"thenn
lua中的引用与拷贝
「已注销」
lua 深拷贝 引用
Lua中的基本类型是值传递,只有表是引用传递-----------------例子一x=1y=xy=10print(x)--输出:1-----------------例子二functionchange(x)x=10endy=1change(y)print(y)--输出:1-----------------例子三x="test"y=xx="show"print(y)--输出:test--------
lua的深拷贝和浅拷贝
一起去放牛
lua junit 开发语言
浅拷贝:这种就是直接把内存地址给了shadow_copy,两个表共享内存,改shadow_copy和orig都会改变表orig的值。深拷贝:这种是递归复制表元素,两个表相互独立不受影响。深拷贝的代码就是另开了个数组,把orig的值穿进去这是跟值类型和引用类型的原理比较相似--原表localorig={name="John",age=30,languages={"Java","Python"}}--
Lua 拷贝
z2014z
lua 开发语言
Lua拷贝主要分为两类:浅拷贝、深拷贝浅拷贝使用赋值运算符=,就是浅拷贝,有两种情况1.拷贝对象是基本的值类型,如string、number、boolean等,赋值时,会创建一个新对象,修改拷贝的值不会影响原来的值2.拷贝的对象是table时,相当于直接进行引用,指向同一个内存地址,修改新对象的值会影响原来的值深拷贝由于Lua没有提供api,需要封装函数,通过递归遍历table拷贝对应数据func
【lua实战】数组和数组长度
经云
lua lua 开发语言
大多数编程语言中,一个数组很容易计算数组长度,一般都是使用现成的函数或者通过计算得到,比如:Pythonarray=[1,2,3,4,5]length=len(array)JavaScriptletarray=[1,2,3,4,5];letlength=array.length;Javaint[]array={1,2,3,4,5};intlength=array.length;C#int[]arr
WRK的使用-lua脚本POST请求(静态数据)
weixin_30390075
lua json
HTTP_prot={"/gateway/services","/gateway/services",}--接口类型HTTP_type={"POST","POST",}--参数HTTP_body={'{"phone":"19012000335"}','{"phone":"19012000335","code":"1569"}',--双中括号里面不转译}-----------如果有多个接口,名称、类
freeswitch中lua脚本支持的函数有哪些?
岁月小龙
lua 开发语言 freeswitch
staticswig_lua_methodswig_CoreSession_methods[]={{"insertFile",_wrap_CoreSession_insertFile},{"answer",_wrap_CoreSession_answer},{"print",_wrap_CoreSession_print},{"preAnswer",_wrap_CoreSession_preAns
lua脚本使用,单个及多个参数post请求
负熵流
服务器 lua 开发语言
1、脚本内容access_token_check.lua:token=ngx.req.get_headers()['token']if(token==nilortoken=='')thenngx.header['Content-Type']='application/json;charset=utf-8'ngx.print('{"errorCode":"401","value":"无访问权限!",
[GPU与CPU100倍性能之谜,论文个人阅读分享]Debunking the 100X GPU vs. CPU myth: an evaluation of throughput computing
GutsShinyHero
杂项学习 性能优化 gpu算力
Debunkingthe100XGPUvs.CPUmyth:anevaluationofthroughputcomputingonCPUandGPU*Authors:VictorW.Lee,ChangkyuKim,JatinChhugani,MichaelDeisher,DaehyunKim,AnthonyD.Nguyen,NadathurSatish,MikhailSmelyanskiy,Sri
Lua一维数组与多维数组的使用示例例子解析
乔丹搞IT
lua非常实用的脚本 lua 开发语言
代码示例:Lua是一种轻量级的脚本语言,它在处理数组时与许多其他编程语言有所不同。Lua中的数组是基于表(table)的,这意味着即使是一维数组也可以看作是特殊的表。一维数组在Lua中,一维数组可以通过索引来访问和修改元素。索引从1开始,而不是从0开始,这是Lua的一个特点。创建一维数组--创建一个一维数组localarray={10,20,30,40,50}访问一维数组元素--访问第一个元素pr
最全金融数据_PySpark-3(2),大数据开发学习的三个终极问题及学习路线规划
2401_84185145
大数据 面试 学习
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新需要这份系统化资料的朋友,可以戳这里获取frompyspark.ml.evaluationimportBinaryClassificationEv
Unity3D项目中如何正确使用Lua详解
Clank的游戏栈
lua junit 开发语言
在Unity3D游戏开发中,Lua作为一种轻量级、灵活且易于学习的脚本语言,被广泛用于游戏逻辑编写、扩展和定制。Lua的集成不仅提高了游戏开发的效率和灵活性,还方便了游戏后期的维护和更新。本文将详细介绍如何在Unity3D项目中正确使用Lua,包括技术详解和代码实现。对惹,这里有一个游戏开发交流小组,大家可以点击进来一起交流一下开发经验呀!Lua的优势轻量级:Lua具有快速的解析和执行速度,非常适
为什么人工智能要用Python?答案在这里_为什么ai技术要用python
2401_84140628
程序员 人工智能 python 开发语言
2、Python的开发生态成熟,有很多库可以用Python灵活的语法还使得包括文本操作、list/dictcomprehension等非常实用的功能非常容易高效实现(bbs.cnitedu.cn),配合lambda等使用更是方便。这也是Python良性生态背后的一大原因。相比而言,Lua虽然也是解释语言,甚至有LuaJIT这种神器加持,但其本身很难做到Python这样,一是因为有Python这个前
高并发 Nginx + lua是如何抗住的
邹志全
提到高并发或者抗压力,有这种高qps经验的同学第一反应大都是Nginx+lua+Redis,网上也满天非那种高并发架构方案大都是这种,但是Nginx+lua来做接入层到底是怎么抗住压力的呢?本篇顺序:1、Nginx如何抗住的高并发,工作模式是怎样的,利用了哪些技术2、常见的IO模型及异步非阻塞IO的优势3、epoll相对于其他模型为何这么强大第一阶段:Nginx不同于Apache的一点就是,Ngi
第T4周:使用TensorFlow实现猴痘病识别
oufoc
tensorflow 人工智能 python
本文为365天深度学习训练营中的学习记录博客原作者:K同学啊文章目录一、前期工作1.设置GPU(如果使用的是CPU可以忽略这步)2.导入数据3.查看数据二、数据预处理1、加载数据2、数据可视化3、再次检查数据4、配置数据集三、构建CNN网络四、编译五、训练模型六、模型评估1.Loss与Accuracy图2.指定图片进行预测七、优化1、使用`model.evaluate`使用测试集评估模型2、网络结
EasyExcel 导入计算公式导出展示字符串问题(SUM)
carry杰
JAVA java
导出自定义表单结果遇到SUM函数时没有算出结果,直接展示的函数字符串处理思路拦截公式字符串:将对应的cell设置setCellFormula字符串公式然后cell类型设置为CellType.FORMULA重新配置这样就解决了问题。注意先设置CellFormula然后设置CellType(我把顺序搞反了,调试了很久)3这里用的是evaluateFormulaCell而不是evaluateInCell
Redis:支撑高并发及高可用复杂的缓存架构
玉成226
【Redis】 缓存 redis 架构
这里写目录标题一、企业级Redis集群架构二、(nginx+lua)+redis+ehcache的三级缓存架构三、数据库+缓存双写一致性解决方案四、大key:缓存维度拆分解决方案五、如何提高缓存的命中率一、企业级Redis集群架构二、(nginx+lua)+redis+ehcache的三级缓存架构三、数据库+缓存双写一致性解决方案四、大key:缓存维度拆分解决方案五、如何提高缓存的命中率
phpredis执行LUA脚本示例代码例子解析
乔丹搞IT
lua非常实用的脚本 lua 开发语言
代码示例:在PHP中使用phpredis扩展执行LUA脚本是一种高效的方式来批量处理Redis命令,这样可以减少网络开销并保证操作的原子性。以下是一个详细的示例代码,展示了如何使用phpredis执行LUA脚本:$redis=newRedis();$redis->connect('127.0.0.1',6379);//LUA脚本$lua=0thenkw_ids=redis.call('sinter
谷粒商城实战笔记-275~276-商城业务-订单服务-订单确认页完成
小手追梦
谷粒商城 笔记 谷粒商城
文章目录一,275-商城业务-订单服务-订单确认页完成1,防止订单重复提交二,276-商城业务-订单服务-原子验令牌Lua脚本Java代码包括内容:275-商城业务-订单服务-订单确认页完成276-商城业务-订单服务-原子验令牌一,275-商城业务-订单服务-订单确认页完成这一节的主要内容是:分析用户点击“提交订单”时,前端发送给后台的数据,包括token,总金额,收货地址,支付方式publicc
2022-Java 后端工程师面试指南 -(Redis)
倾听铃的声
后端 redis java 面试 分布式 经验分享
说说什么是redis吧Redis是一个开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。它支持数据结构,例如字符串,哈希,列表,集合,带范围查询的排序集合,位图,超日志,带有半径查询和流的地理空间索引。Redis具有内置的复制,Lua脚本,LRU逐出,事务和不同级别的磁盘持久性,并通过RedisSentinel和RedisCluster自动分区提供了高可用性。说说Redis
XLua_热更新学习四,使用lua脚本热更新
菜鸟的笔记
上一篇搭建好了lua虚拟环境(点击查看),本篇利用搭建好的虚拟环境尝试着进行XLua热更新1.先创建项目,写好业务代码(例子)1.1创建Button,和脚本NewBehaviourScript(挂在Button上)1.2代码如下usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingUnityEng
通过断点调试lua
_Bruce
lua cocos2d lua cocos2d 断点
1、首先安装vs2012及以上的版本;2、下载BabeLua安装包,下载地址:http://pan.baidu.com/s/1qXUtrC43、安装BabeLua,双击安装就可以,这个插件类似于番茄插件;4、启动vs,验证安装,在主菜单是看见LUA就是安装成功了;5、配置项目:配置后保存,在上边选择刚刚配置的项目打开,并将其设置成启动项,完整界面见下图:注意下Workingpath,在我们设置完L
html
周华华
html
js
1,数组的排列
var arr=[1,4,234,43,52,];
for(var x=0;x<arr.length;x++){
for(var y=x-1;y<arr.length;y++){
if(arr[x]<arr[y]){
&
【Struts2 四】Struts2拦截器
bit1129
struts2拦截器
Struts2框架是基于拦截器实现的,可以对某个Action进行拦截,然后某些逻辑处理,拦截器相当于AOP里面的环绕通知,即在Action方法的执行之前和之后根据需要添加相应的逻辑。事实上,即使struts.xml没有任何关于拦截器的配置,Struts2也会为我们添加一组默认的拦截器,最常见的是,请求参数自动绑定到Action对应的字段上。
Struts2中自定义拦截器的步骤是:
make:cc 命令未找到解决方法
daizj
linux 命令未知 make cc
安装rz sz程序时,报下面错误:
[root@slave2 src]# make posix
cc -O -DPOSIX -DMD=2 rz.c -o rz
make: cc:命令未找到
make: *** [posix] 错误 127
系统:centos 6.6
环境:虚拟机
错误原因:系统未安装gcc,这个是由于在安
Oracle之Job应用
周凡杨
oracle job
最近写服务,服务上线后,需要写一个定时执行的SQL脚本,清理并更新数据库表里的数据,应用到了Oracle 的 Job的相关知识。在此总结一下。
一:查看相关job信息
1、相关视图
dba_jobs
all_jobs
user_jobs
dba_jobs_running 包含正在运行
多线程机制
朱辉辉33
多线程
转至http://blog.csdn.net/lj70024/archive/2010/04/06/5455790.aspx
程序、进程和线程:
程序是一段静态的代码,它是应用程序执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程。线程是比进程更小的单位,一个进程执行过程中可以产生多个线程,每个线程有自身的
web报表工具FineReport使用中遇到的常见报错及解决办法(一)
老A不折腾
web报表 finereport java报表 报表工具
FineReport使用中遇到的常见报错及解决办法(一)
这里写点抛砖引玉,希望大家能把自己整理的问题及解决方法晾出来,Mark一下,利人利己。
出现问题先搜一下文档上有没有,再看看度娘有没有,再看看论坛有没有。有报错要看日志。下面简单罗列下常见的问题,大多文档上都有提到的。
1、address pool is full:
含义:地址池满,连接数超过并发数上
mysql rpm安装后没有my.cnf
林鹤霄
没有my.cnf
Linux下用rpm包安装的MySQL是不会安装/etc/my.cnf文件的,
至于为什么没有这个文件而MySQL却也能正常启动和作用,在这儿有两个说法,
第一种说法,my.cnf只是MySQL启动时的一个参数文件,可以没有它,这时MySQL会用内置的默认参数启动,
第二种说法,MySQL在启动时自动使用/usr/share/mysql目录下的my-medium.cnf文件,这种说法仅限于r
Kindle Fire HDX root并安装谷歌服务框架之后仍无法登陆谷歌账号的问题
aigo
root
原文:http://kindlefireforkid.com/how-to-setup-a-google-account-on-amazon-fire-tablet/
Step 4: Run ADB command from your PC
On the PC, you need install Amazon Fire ADB driver and instal
javascript 中var提升的典型实例
alxw4616
JavaScript
// 刚刚在书上看到的一个小问题,很有意思.大家一起思考下吧
myname = 'global';
var fn = function () {
console.log(myname); // undefined
var myname = 'local';
console.log(myname); // local
};
fn()
// 上述代码实际上等同于以下代码
m
定时器和获取时间的使用
百合不是茶
时间的转换 定时器
定时器:定时创建任务在游戏设计的时候用的比较多
Timer();定时器
TImerTask();Timer的子类 由 Timer 安排为一次执行或重复执行的任务。
定时器类Timer在java.util包中。使用时,先实例化,然后使用实例的schedule(TimerTask task, long delay)方法,设定
JDK1.5 Queue
bijian1013
java thread java多线程 Queue
JDK1.5 Queue
LinkedList:
LinkedList不是同步的。如果多个线程同时访问列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方
http认证原理和https
bijian1013
http https
一.基础介绍
在URL前加https://前缀表明是用SSL加密的。 你的电脑与服务器之间收发的信息传输将更加安全。
Web服务器启用SSL需要获得一个服务器证书并将该证书与要使用SSL的服务器绑定。
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后
【Java范型五】范型继承
bit1129
java
定义如下一个抽象的范型类,其中定义了两个范型参数,T1,T2
package com.tom.lang.generics;
public abstract class SuperGenerics<T1, T2> {
private T1 t1;
private T2 t2;
public abstract void doIt(T
【Nginx六】nginx.conf常用指令(Directive)
bit1129
Directive
1. worker_processes 8;
表示Nginx将启动8个工作者进程,通过ps -ef|grep nginx,会发现有8个Nginx Worker Process在运行
nobody 53879 118449 0 Apr22 ? 00:26:15 nginx: worker process
lua 遍历Header头部
ronin47
lua header 遍历
local headers = ngx.req.get_headers()
ngx.say("headers begin", "<br/>")
ngx.say("Host : ", he
java-32.通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小(两数组的差最小)。
bylijinnan
java
import java.util.Arrays;
public class MinSumASumB {
/**
* Q32.有两个序列a,b,大小都为n,序列元素的值任意整数,无序.
*
* 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
* 例如:
* int[] a = {100,99,98,1,2,3
redis
开窍的石头
redis
在redis的redis.conf配置文件中找到# requirepass foobared
把它替换成requirepass 12356789 后边的12356789就是你的密码
打开redis客户端输入config get requirepass
返回
redis 127.0.0.1:6379> config get requirepass
1) "require
[JAVA图像与图形]现有的GPU架构支持JAVA语言吗?
comsci
java语言
无论是opengl还是cuda,都是建立在C语言体系架构基础上的,在未来,图像图形处理业务快速发展,相关领域市场不断扩大的情况下,我们JAVA语言系统怎么从这么庞大,且还在不断扩大的市场上分到一块蛋糕,是值得每个JAVAER认真思考和行动的事情
安装ubuntu14.04登录后花屏了怎么办
cuiyadll
ubuntu
这个情况,一般属于显卡驱动问题。
可以先尝试安装显卡的官方闭源驱动。
按键盘三个键:CTRL + ALT + F1
进入终端,输入用户名和密码登录终端:
安装amd的显卡驱动
sudo
apt-get
install
fglrx
安装nvidia显卡驱动
sudo
ap
SSL 与 数字证书 的基本概念和工作原理
darrenzhu
加密 ssl 证书 密钥 签名
SSL 与 数字证书 的基本概念和工作原理
http://www.linuxde.net/2012/03/8301.html
SSL握手协议的目的是或最终结果是让客户端和服务器拥有一个共同的密钥,握手协议本身是基于非对称加密机制的,之后就使用共同的密钥基于对称加密机制进行信息交换。
http://www.ibm.com/developerworks/cn/webspher
Ubuntu设置ip的步骤
dcj3sjt126com
ubuntu
在单位的一台机器完全装了Ubuntu Server,但回家只能在XP上VM一个,装的时候网卡是DHCP的,用ifconfig查了一下ip是192.168.92.128,可以ping通。
转载不是错:
Ubuntu命令行修改网络配置方法
/etc/network/interfaces打开后里面可设置DHCP或手动设置静态ip。前面auto eth0,让网卡开机自动挂载.
1. 以D
php包管理工具推荐
dcj3sjt126com
PHP Composer
http://www.phpcomposer.com/
Composer是 PHP 用来管理依赖(dependency)关系的工具。你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件。
中文文档
入门指南
下载
安装包列表
Composer 中国镜像
Gson使用四(TypeAdapter)
eksliang
json gson Gson自定义转换器 gsonTypeAdapter
转载请出自出处:http://eksliang.iteye.com/blog/2175595 一.概述
Gson的TypeAapter可以理解成自定义序列化和返序列化 二、应用场景举例
例如我们通常去注册时(那些外国网站),会让我们输入firstName,lastName,但是转到我们都
JQM控件之Navbar和Tabs
gundumw100
html xml css
在JQM中使用导航栏Navbar是简单的。
只需要将data-role="navbar"赋给div即可:
<div data-role="navbar">
<ul>
<li><a href="#" class="ui-btn-active&qu
利用归并排序算法对大文件进行排序
iwindyforest
java 归并排序 大文件 分治法 Merge sort
归并排序算法介绍,请参照Wikipeida
zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F
基本思想:
大文件分割成行数相等的两个子文件,递归(归并排序)两个子文件,直到递归到分割成的子文件低于限制行数
低于限制行数的子文件直接排序
两个排序好的子文件归并到父文件
直到最后所有排序好的父文件归并到输入
iOS UIWebView URL拦截
啸笑天
UIWebView
本文译者:candeladiao,原文:URL filtering for UIWebView on the iPhone说明:译者在做app开发时,因为页面的javascript文件比较大导致加载速度很慢,所以想把javascript文件打包在app里,当UIWebView需要加载该脚本时就从app本地读取,但UIWebView并不支持加载本地资源。最后从下文中找到了解决方法,第一次翻译,难免有
索引的碎片整理SQL语句
macroli
sql
SET NOCOUNT ON
DECLARE @tablename VARCHAR (128)
DECLARE @execstr VARCHAR (255)
DECLARE @objectid INT
DECLARE @indexid INT
DECLARE @frag DECIMAL
DECLARE @maxfrag DECIMAL
--设置最大允许的碎片数量,超过则对索引进行碎片
Angularjs同步操作http请求with $promise
qiaolevip
每天进步一点点 学习永无止境 AngularJS 纵观千象
// Define a factory
app.factory('profilePromise', ['$q', 'AccountService', function($q, AccountService) {
var deferred = $q.defer();
AccountService.getProfile().then(function(res) {
hibernate联合查询问题
sxj19881213
sql Hibernate HQL 联合查询
最近在用hibernate做项目,遇到了联合查询的问题,以及联合查询中的N+1问题。
针对无外键关联的联合查询,我做了HQL和SQL的实验,希望能帮助到大家。(我使用的版本是hibernate3.3.2)
1 几个常识:
(1)hql中的几种join查询,只有在外键关联、并且作了相应配置时才能使用。
(2)hql的默认查询策略,在进行联合查询时,会产
struts2.xml
wuai
struts
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache