lua c api agile Posted on Sep 16 2023 面试 lua ###table相关api --- ```c lua_createtable 原型: void lua_createtable (lua_State *L, int narr, int nrec); 描述: 创建一个新的table并将之放在栈顶.narr是该table数组部分的长度,nrec是该table hash部分的长度. 当我们确切的知道要放多少元素到table的时候,使用这个函数,lua可以预分配一些内存,提升性能. 如果不确定要存放多少元素可以使用 lua_newtable 函数来创建table. lua_newtable 原型: void lua_newtable (lua_State *L); 描述: 创建一个新的table并将之放在栈顶. 等同于lua_createtable(L, 0, 0). lua_getfield 原型: void lua_getfield (lua_State *L, int index, const char *k); 描述: 将t[k]元素push到栈顶. 其中t是index处的table. 这个函数可能触发index元方法. lua_setfield 原型: void lua_setfield (lua_State *L, int index, const char *k); 描述: 为table中的key赋值. t[k] = v . 其中t是index处的table , v为栈顶元素. 这个函数可能触发newindex元方法. 调用完成后弹出栈顶元素(value). lua_gettable 原型: void lua_gettable (lua_State *L, int index); 描述: 将t[k]元素push到栈顶. 其中t是index处的table,k为栈顶元素. 这个函数可能触发index元方法. 调用完成后弹出栈顶元素(key). lua_settable 原型: void lua_settable (lua_State *L, int index); 描述: 为table中的key赋值. t[k] = v . 其中t是index处的table , v为栈顶元素. k为-2处的元素. 这个函数可能触发newindex元方法. 调用完成后弹出栈顶两个元素(key , value) lua_rawget 原型: void lua_rawget (lua_State *L, int index); 描述: 与lua_gettable函数类似, 但是不会触发index元方法. lua_rawset 原型: void lua_rawset (lua_State *L, int index); 描述: 与lua_settable函数类似, 但是不会触发newindex元方法. lua_rawgeti 原型: void lua_rawgeti (lua_State *L, int index, int n); 描述: 将t[n]元素push到栈顶.其中t是index处的table. 这个函数不会触发index元方法. lua_rawseti 原型: void lua_rawseti (lua_State *L, int index, int n); 描述: 为table中的key赋值. t[n] = v .其中t是index处的table , v为栈顶元素. 这个函数不会触发newindex元方法. 调用完成后弹出栈顶元素. lua_rawgetp 原型: void lua_rawgetp (lua_State *L, int index, const void *p); 描述: 将t[p]元素push到栈顶.其中t是index处的table. p是一个lightuserdata. 这个函数不会触发index元方法. lua_rawsetp 原型: void lua_rawsetp (lua_State *L, int index, const void *p); 描述: 为table中的key赋值. t[p] = v .其中t是index处的table , p是一个lightuserdata , v为栈顶元素. 这个函数不会触发newindex元方法. 调用完成后弹出栈顶元素. lua_getmetatable 原型: int lua_getmetatable (lua_State *L, int index); 描述: 将index处元素的元表push到栈顶. 如果该元素没有元表, 函数返回0 , 不改变栈. lua_setmetatable 原型: void lua_setmetatable (lua_State *L, int index); 描述: 将栈顶元素设置为index处元素的元表. 调用完成后弹出栈顶元素. lua_istable 原型: int lua_istable (lua_State *L, int index); 描述: 判断index处元素是否为一个table , 如果是返回1,否则返回0. lua_pushglobaltable 原型: void lua_pushglobaltable (lua_State *L); 描述: 将lua的全局表放在栈顶. luaL_newmetatable 原型: int luaL_newmetatable (lua_State *L, const char *tname); 描述: 如果注册表中已经有名为tname的key,则返回0. 否则创建一个新table作为userdata的元表. 这个元表存储在注册表中,并以tname为key. 返回1. 函数完成后将该元表置于栈顶. luaL_getmetatable 原型: void luaL_getmetatable (lua_State *L, const char *tname); 描述: 将注册表中以tname为key的元表push到栈顶. luaL_setmetatable 原型: void luaL_setmetatable (lua_State *L, const char *tname); 描述: 将栈顶元素存储到注册表中, 它的key为tname. /* 检查虚拟栈中索引"arg"处的值是否为一个"userdata", * 并且此"userdata"具有一个名为"tname"的"metatable"。 * 如果是,则返回此"userdata"的地址,否则返回"NULL"。 */ void *luaL_checkudata (lua_State *L, int arg, const char *tname); luaL_getsubtable 原型: int luaL_getsubtable (lua_State *L, int idx, const char *fname); 描述: 将 t[fname] push到栈顶, 其中t是index处的table , 并且 t[fname] 也为一个table. 如果 t[fname] 原本就存在,返回 true ,否则返回false,并且将 t[fname] 新建为一张空表. lua_getglobal 原型: void lua_getglobal (lua_State *L, const char *name); 描述: 将 t[name] 元素push到栈顶, 其中t为全局表. lua_setglobal 原型: void lua_setglobal (lua_State *L, const char *name); 描述: 为table中的key赋值. t[name] = v . 其中t为全局表. v为栈顶元素. 调用完成后弹出栈顶元素(v). luaL_newlibtable 原型: void luaL_newlibtable (lua_State *L, const luaL_Reg l[]); 描述: 创建一张空表, lua预先分配足够的内存用来存储我们创建的函数库. 稍后我们可以使用 luaL_setfuncs 函数注册我们的函数库. luaL_setfuncs 原型: void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); 描述: 将所有 luaL_Reg数组中的函数注册到栈顶的table中. 当upvalue个数不为0时,所创建的所有函数共享这些upvalue. -2到-(nup+1)的元素为要注册的upvalue. (注意:这些upvalue是c中的upvalue,不是lua中的upvalue,可以在注册的c函数中通过 lua_upvalueindex(n)获取其值.) 调用完成后弹出栈顶的所有upvalue. luaL_newlib 原型: void luaL_newlib (lua_State *L, const luaL_Reg *l); 描述: 创建一个新的table , 并将luaL_Reg数组中的函数注册到其中. 它是一个宏 (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) lua_next 原型: int lua_next (lua_State *L, int index); 描述: 该函数用来遍历一个table. 从栈顶弹出一个key , 并且push一个 key-value对(栈顶key的下一个键值对) ,到栈顶. 如果table中没有更多的元素, 函数返回0. 遍历开始时栈顶为一个nil , 函数取出第一个键值对. 通常遍历方法为: lua_pushnil(L); // first key while (lua_next(L, t) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); // removes 'value'; keeps 'key' for next iteration lua_pop(L, 1); } 注意: 在遍历table的时候 ,除非明确的知道key为字符串,不要对栈上的key使用 lua_tolstring 函数 , 因为这样有可能改变key的类型 , 影响下一次 lua_next调用. lua_rawlen 原型: size_t lua_rawlen (lua_State *L, int index); 描述: 获取index处元素的长度. 对于字符串来说,返回字符串长度. 对于table来说,返回#操作符的长度. 不受元方法影响. 对于userdata来说,返回内存的大小. 其他元素返回0. lua_len 原型: void lua_len (lua_State *L, int index); 描述: 获取index处元素#操作符的结果 , 放置在栈顶. 其他概念: 1.伪索引: Lua栈的正常索引 从栈顶算,栈顶为-1,向栈低递减. 从栈低算,栈低为1,向栈顶递增. 伪索引是一种索引,他不在栈的位置中,通过一个宏来定义伪索引的位置. 伪索引被用来访问注册表,或者在lua_CFunction中访问upvalue. 2.注册表: Lua的注册表是一个预定义的table, 可以提供给c api存储一切想要存储的值. 注册表通过 LUA_REGISTRYINDEX 伪索引来访问. 例如 lua_getfield 函数可以像下面这样使用来获取注册表中的一个以"hello"为key的值 : lua_getfield( L , LUA_REGISTRYINDEX , "hello"); 3. upvalue: 在使用 lua_pushcfunction 或者 luaL_setfuncs 将一个lua_CFunction 注册到Lua环境中时, 可以同时为这个函数设置一些upvalue . 而后在这些lua_CFunction 中可以使用 lua_upvalueindex(n) 函数来获取对应位置的upvalue. ``` --- ###元素入栈出栈 --- ####入栈 ```C // 将"b"作为一个布尔值入栈。 void lua_pushboolean(lua_State *L, int b) /* 将C函数"fn"以及其在虚拟栈上关联的"n"个值作为"Closure"入栈。 * "n"最大为255,第一个被关联的值首先入栈,栈顶是最后一个被关联的值, * 这些值会在函数调用成功后被出栈。 */ void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n) // 将C函数"f"作为函数入栈。内部实际调用"lua_pushcclosure(L, f, 0)"。 void lua_pushcfunction(lua_State *L, lua_CFunction f) /* 将一个被格式化后的字符串入栈。函数返回这个字符串的指针。 * 与C语言中的"sprintf()"类似,其区别在于: * 1、不需要为结果分配空间。 * 其结果是一个Lua字符串,由Lua来关心其内存分配(同时通过垃圾收集来释放内存)。 * 2、"fmt"不支持符号、宽度、精度。只支持: * "%%": 字符'%'。 * "%s": 带零终止符的字符串,没有长度限制。 * "%f": "lua_Number"(Lua中的浮点数类型)。 * "%L": "lua_Integer"(Lua中的整数类型)。 * "%p": 指针或是一个十六进制数。 * "%d": "int"。 * "%c": "char"。 * "%U": 用"long int"表示的UTF-8字。 */ const char *lua_pushfstring(lua_State *L, const char *fmt, ...) /* 将长度为"len",非字面形式的字符串"s"入栈。 * Lua对这个字符串做一个内部副本(或是复用一个副本), * 因此"s"处的内存在函数返回后,可以释放掉或是立刻重用于其它用途。 * 字符串内可以是任意二进制数据,包括'\0'。函数返回内部副本的指针。 */ const char *lua_pushlstring(lua_State *L, const char *s, size_t len) // 将字面形式的字符串"s"入栈,函数自动给出字符串的长度。返回内部副本的指针。 const char *lua_pushliteral(lua_State *L, const char *s) /* 将以'\0'结尾的字符串"s"入栈。 * Lua对这个字符串做一个内部副本(或是复用一个副本), * 因此"s"处的内存在函数返回后,可以释放掉或是立刻重用于其它用途。 * 函数返回内部副本的指针。如果"s"为"NULL",将"nil"入栈并返回"NULL"。 */ const char *lua_pushstring(lua_State *L, const char *s) // 等价于"lua_pushfstring()"。不过是用"va_list"接收参数,而不是用可变数量的实际参数。 const char *lua_pushvfstring(lua_State *L, const char *fmt, va_list argp) // 将全局环境入栈。 void lua_pushglobaltable(lua_State *L) // 将值为"n"的整数入栈。 void lua_pushinteger(lua_State *L, lua_Integer n) /* 将一个轻量用户数据"p"入栈。 * 用户数据是保留在Lua中的C值。轻量用户数据表示一个指针"void*"。 * 它像一个数值,你不需要专门创建它,它也没有独立的元表, * 而且也不会被收集(因为从来不需要创建)。只要表示的C地址相同,两个轻量用户数据就相等。 */ void lua_pushlightuserdata(lua_State *L, void *p) // 将空值入栈。 void lua_pushnil(lua_State *L) // 将一个值为"n"的浮点数入栈。 void lua_pushnumber(lua_State *L, lua_Number n) // "L"表示的线程入栈。如果这个线程是当前状态机的主线程的话,返回1。 int lua_pushthread(lua_State *L) // 将虚拟栈上索引"index"处的元素的副本入栈。 void lua_pushvalue(lua_State *L, int index) ``` --- ####出栈 --- ```C // 从虚拟栈中弹出"n"个元素。 void lua_pop(lua_State *L, int n) ``` --- ###检查虚拟栈中元素的类型 --- ```C // 如果栈中索引"index"处的元素为"bool"类型,则返回1,否则返回0。 int lua_isboolean(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个C函数,则返回1,否则返回0。 int lua_iscfunction(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个C函数或是一个Lua函数,则返回1,否则返回0。 int lua_isfunction(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个整数,则返回1,否则返回0。 int lua_isinteger(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个轻量级的"userdata",则返回1,否则返回0。 int lua_islightuserdata(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个"nil",则返回1,否则返回0。 int lua_isnil(lua_State *L, int index // 如果"index"是一个无效索引时,返回1,否则返回0。 int lua_isnone(lua_State *L, int index) // 如果"index"是一个无效索引或者"index"处的元素是一个"nil",则返回1,否则返回0。 int lua_isnoneornil(lua_State *L, int index) /* 如果栈中索引"index"处的元素是一个数值或者是一个可以转换为数值的字符串, * 则返回1,否则返回0。 */ int lua_isnumber(lua_State *L, int index) /* 如果栈中索引"index"处的元素是一个字符串或者是一个可以转换为字符串的数值, * 则返回1,否则返回0。 */ int lua_isstring(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个"table",则返回1,否则返回0。 int lua_istable(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个线程,则返回1,否则返回0。 int lua_isthread(lua_State *L, int index) // 如果栈中索引"index"处的元素是一个"userdata",则返回1,否则返回0。 int lua_isuserdata (lua_State *L, int index) // 如果栈中的"coroutine"可以被挂起,则返回1,否则返回0。 int lua_isyieldable(lua_State *L) /* 返回栈中索引"index"处元素的类型。这些类型在"lua.h"中定义,如下: * #define LUA_TNONE (-1) // 无效 * #define LUA_TNIL 0 // "nil" * #define LUA_TBOOLEAN 1 // "bool" * #define LUA_TLIGHTUSERDATA 2 // 轻量级"userdata" * #define LUA_TNUMBER 3 // 数值 * #define LUA_TSTRING 4 // 字符串 * #define LUA_TTABLE 5 // "table" * #define LUA_TFUNCTION 6 // 函数 * #define LUA_TUSERDATA 7 // "userdata" * #define LUA_TTHREAD 8 // 线程 */ int lua_type(lua_State *L, int index) // 返回"tp"表示的类型的名字。"tp"是"lua_type()"的返回值之一。 const char *lua_typename(lua_State *L, int tp) ``` --- ###转换虚拟栈中元素的类型 --- ```C // 将栈中"index"处的元素转换为C中的"bool"值返回。 int lua_toboolean(lua_State *L, int index) // 将栈中"index"处的元素转换为一个C函数返回。指定的元素必须是一个C函数,否则返回"NULL"。 lua_CFunction lua_tocfunction(lua_State *L, int index) /* 将栈中"index"处的元素转换为一个整数返回。 * 指定的元素必须是一个整数或是一个可以被转换为整数的数字或字符串,否则返回0。 * 如果"isnum"非"NULL","*isnum"会被赋值为操作是否成功的"bool"值。 */ lua_Integer lua_tointegerx(lua_State *L, int index, int *isnum) // 内部调用"lua_tointegerx(L, index, NULL)"。 lua_Integer lua_tointeger(lua_State *L, int index) /* 将栈中"index"处的元素转换为一个C字符串并将其指针返回。 * 如果"len"非"NULL","*len"将获得字符串的长度。 * 指定元素必须是一个字符串或是一个数字,否则返回返回"NULL"。 * 如果指定元素是一个数字,函数会将元素的类型转换为字符串。 * 返回的字符串结尾包含'\0',而在字符串中允许包含多个'\0'。 * 函数返回的字符串应立即转存,否则有可能被Lua垃圾回收器回收。 */ const char *lua_tolstring(lua_State *L, int index, size_t *len) /* 将栈中"index"处的元素转换为一个浮点数返回。 * 指定的元素必须是一个数字或是一个可被转换为数字的字符串,否则返回0。 * 如果"isnum"非"NULL","*isnum"会被赋值为操作是否成功的"bool"值。 */ lua_Number lua_tonumberx(lua_State *L, int index, int *isnum) // 内部调用"lua_tonumberx(L, index, NULL)"。 lua_Number lua_tonumber(lua_State *L, int index) /* 将栈中"index"处的元素转换为一个C指针返回。 * 指定的元素必须是一个"userdata","table",线程或是一个函数,否则返回"NULL"。 */ const void *lua_topointer(lua_State *L, int index) // 内部调用"lua_tolstring(L, index, NULL)"。 const char *lua_tostring(lua_State *L, int index) /* 将栈中"index"处的元素转换为一个Lua线程返回。 * 指定的元素必须是一个线程,否则返回"NULL"。 */ lua_State *lua_tothread(lua_State *L, int index) /* 栈中"index"处的元素如果是一个完全"userdata",则返回其内存地址的指针; * 如果是一个轻量级"userdata",则返回其存储的指针。 */ void *lua_touserdata(lua_State *L, int index) ``` --- ###维护虚拟栈的方法 --- ```C /* * 返回栈顶元素的索引。 * 因为栈中元素的索引是从1开始编号的,所以函数的返回值相当于栈中元素的个数。 * 返回值为0表示栈为空。 */ int lua_gettop(lua_State *L); // 返回栈中元素的个数。 /* * 设置栈顶为索引"index"指向处。 * 如果"index"比"lua_gettop()"的值大,那么多出的新元素将被赋值为"nil"。 */ void lua_settop(lua_State *L, int index); // 清空栈。 /* * 移除栈中索引"index"处的元素,该元素之上的所有元素下移。 */ void lua_remove(lua_State *L, int index); /* * 将栈顶元素移动到索引"index"处,索引"index"(含)之上的所有元素上移。 */ void lua_insert(lua_State *L, int index); /* * 将栈顶元素移动到索引"index"处。(相当于覆盖了索引"index"处的元素) */ void lua_replace(lua_State *L, int index); ``` --- ###灵活的操作Lua的`table` --- ```C //从虚拟栈中"index"处获得"table",栈顶获得"value", //栈顶下面一个元素获得"key"。相当于在Lua环境中执行"table[key] = value"命令, //设置"table[key]"的过程有可能触发"metamethods"(__newindex)。 //函数在执行结束后,会弹出"key"和"value"。 void lua_settable(lua_State *L, int index); //从虚拟栈中"index"处获得"table",栈顶获得"key", //从Lua环境中获取"table[key]"的值。 //获取"table[n]"的过程有可能触发"metamethods"(__index)。 //函数在执行结束后,会弹出"key",并将结果放在虚拟栈上。 int lua_gettable(lua_State *L, int index); //功能类似于"lua_settable()",但过程中不会触发"metamethods"(__newindex)。 void lua_rawset(lua_State *L, int index); //功能类似于"lua_gettable()",但过程中不会触发"metamethods"(__index)。 int lua_rawget(lua_State *L, int index); //从虚拟栈中"index"处获得"table",栈顶获得"value", //相当于在Lua环境中执行"table[i] = value"命令。 //设置"table[i]"的过程不会触发"metamethods"(__newindex)。 //函数在执行结束后,会弹出"value"。 //其实现相当于: //lua_pushnumber(L, i); //lua_insert(L, -2); -- 将"key"放到"value"的下面。 //lua_rawset(L, index); -- 当"index"是正索引时。 //lua_rawset(L, index - 1); -- 当"index"是负索引时(因为"key"入栈了)。 void lua_rawseti(lua_State *L, int index, lua_Integer i); //从虚拟栈中"index"处获得"table",从Lua环境中获取"table[n]"的值, //并将结果放在虚拟栈上。获取"table[n]"的过程不会触发"metamethods"(__index)。 //其实现相当于: //lua_pushnumber(L, n); //lua_rawget(L, index); int lua_rawgeti(lua_State *L, int index, lua_Integer n); ``` --- ###操作Lua的字符串 --- ```C /* 检查虚拟栈中索引"arg"处的元素是否为字符串,如果是则返回字符串,否则返回"NULL"。 * 函数内部通过"lua_tolstring()"获取结果。 */ const char *luaL_checkstring(lua_State *L, int arg); /* 按照Lua中".."的功能,连接从栈顶开始的"n"个值。 * 函数会将被连接的值出栈,之后将结果入栈。如果"n"为0,则将一个空串入栈。 */ void lua_concat(lua_State *L, int n); /* 专门用于在C库函数中缓存零碎的字符串。 * 有两种使用方式: * 1、结果字符串的长度未知: * (1) 定义一个"luaL_Buffer"类型的缓存(例如,luaL_Buffer b;)。 * (2) 调用"luaL_buffinit"初始化缓存(例如,luaL_buffinit(L, &b);)。 * 初始化之后,"buffer"保留了一份状态"L"的拷贝, * 因此当我们调用其他操作"buffer"的函数的时候不需要再传递"L"。 * (3) 调用"luaL_add*"这一组函数逐一的将字符串放入缓存(例如,luaL_addstring(L, s);)。 * (4) 最后调用"luaL_pushresult"结束对缓存的使用, * 并将结果字符串入栈(例如,luaL_pushresult(&b);)。 * 2、结果字符串的长度已知: * (1) 定义一个"luaL_Buffer"类型的缓存(例如,luaL_Buffer b;)。 * (2) 调用"luaL_buffinitsize",为缓存预分配以及初始化一个指定大小的缓冲区 * (例如,char *p = luaL_buffinitsize(L, &b, sz);)。 * (3) 逐一的将字符串放入缓冲区(例如,p[0] = 字符串;)。 * (4) 最后调用"luaL_pushresultsize"将缓冲区中的字符串放入缓存, * 结束对缓存的使用,并将结果字符串入栈(例如,luaL_pushresultsize(&b, sz))。 * 这里的"sz"是指已经复制到缓存中的字符串长度。 */ typedef struct luaL_Buffer luaL_Buffer; // 向缓存"B"中添加一个字节"c"。 void luaL_addchar(luaL_Buffer *B, char c); // 向缓存"B"中添加一个以'\0'结尾的字符串"s"。 void luaL_addstring(luaL_Buffer *B, const char *s); // 向缓存"B"中添加一个长度为"l"的字符串"s"。"s"中可以包含'\0'。 void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l); // 向缓存"B"中添加一个在缓冲区中长度为"n"的字符串。 void luaL_addsize(luaL_Buffer *B, size_t n); // 将栈顶的值放入缓存"B",随后将该值出栈。 void luaL_addvalue(luaL_Buffer *B); /* 为缓存"B"分配一段大小为"sz"的缓冲区。函数返回缓冲区的地址。 * 你可以向缓冲区中存入字符串,之后必须调用"luaL_addsize"才能真正的将字符串放入缓存。 */ char *luaL_prepbuffsize(luaL_Buffer *B, size_t sz); // 等价于"luaL_prepbuffsize",预定义的缓冲区大小为"LUAL_BUFFERSIZE"(在哪儿定义的!!!)。 char *luaL_prepbuffer(luaL_Buffer *B); /* 初始化缓存"B"。 * 这个函数不会分配任何空间,缓存必须以一个变量的形式声明。 */ void luaL_buffinit(lua_State *L, luaL_Buffer *B); /* * 等价于先调用"luaL_buffinit",再调用"luaL_prepbuffsize"。 */ char *luaL_buffinitsize(lua_State *L, luaL_Buffer *B, size_t sz); // 结束对缓存"B"的使用,将结果字符串入栈。 void luaL_pushresult(luaL_Buffer *B); /* 将于缓存"B"关联的缓冲区中长度为"sz"的字符串放入缓存"B", * 之后结束对缓存"B"的使用,将结果字符串入栈。 * 等价于先调用"luaL_addsize",再调用"luaL_pushresult"。 */ void luaL_pushresultsize(luaL_Buffer *B, size_t sz); ``` --- ###C库函数中实现`Closure` --- ```C /* 创建一个C中的"Closure",将栈顶的"n"个值作为其"upvalues"。 * 弹出栈顶作为"upvalues"的"n"个值,最后将"Closure"入栈。 */ void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n); // 返回当前运行的函数的第"i"个"upvalue"的"pseudo-indice"。 int lua_upvalueindex(int i); ``` --- ####reference system - `referencesystem`由一对儿定义在辅助库中的函数组成。使用他们,你可以无需关心如何创建唯一的`key`,便可以在`registry`中自由的存取数据 --- ```C /* 生成一个唯一的"key",将栈顶的值出栈作为"value", * 从虚拟栈的索引"t"处获得"table",之后做相当于"table[key] = value"的操作。 * 函数返回生成的"key"。 * 如果"value"为"nil",则不会生成"key",同时函数返回"LUA_REFNIL"。 * 同时Lua还定义了"LUA_NOREF",它代表一个与"luaL_ref"所返回的任何值都不同的值。 */ int luaL_ref(lua_State *L, int t); /* 从虚拟栈的索引"t"处获得"table",之后做相当于"table[ref] = nil"的操作。 * "ref"同时也被释放(可以再次供"luaL_ref"使用)。 * 如果"ref"是"LUA_NOREF"或是"LUA_REFNIL",则函数不做任何操作。 */ void luaL_unref(lua_State *L, int t, int ref); ``` --- ###Userdata --- ```c /* 分配一块大小为"size"的内存空间作为"full userdata"使用, * 之后将内存空间的地址入栈,函数返回此地址。 */ void *lua_newuserdata(lua_State *L, size_t size); /* 检查"cond"是否为"true",如果为"false"则报错,并返回形如如下格式的错误, * "bad argument #arg to 'funcname' (extramsg)" */ void luaL_argcheck (lua_State *L, int cond, int arg, const char *extramsg); ``` 0915学习 0912学习