一 概述
在 Lua 中使用 userdata 表示 C 中的复杂数据类型(其实是一块内存区域),对于 uerdata 没有预定义的操作。light userdata 表示指针类型数据,并不需要创建(它是指针值),同时,**light userdata 不被 gc 管理**。ligth userdata 的主要用途是用户自己管理内存,避免 gc 管理内存。
二 使用 userdata 实现数组
在 lua 中使用 table 作为数组,在数组变大时会耗费非常多的内存,使用 userdata 能够降低内存使用。userdata 可以有 metatable,对 userdata 类型进行识别(判断 C 类型是否正确)增加元方法。
1. 示例代码
1 |
|
2. 调用示例
1 | $ /usr/local/lua5.1.5/bin/lua -e "require 'userdata'; arr = array.new(20); print(type(arr)); array.set(arr,1,20);print('arr[1]=',array.get(arr,1));print('size:',array.size(arr))" |
三 添加元方法
在创建元表时可以在元表中添加元方法,方便使用 Lua 的 __index、__newindex 方法。修改 luaopen_userdata 方法实现:
1 | int |
在这里的栈操作要仔细
调用示例
1 | $ /usr/local/lua5.1.5/bin/lua -e "require 'userdata'; arr = array.new(20); print(type(arr)); arr[1]=20;print('arr[1]=',arr[1])" |
四 函数说明
1. lua_newuserdata
1 | void *lua_newuserdata (lua_State *L, size_t size); |
创建一块 size 大小的内存区域,将其压入栈顶并返回内存地址指针。
2. luaL_checkudata
1 | void *luaL_checkudata (lua_State *L, int narg, const char *tname); |
检查函数的第 narg 参数是否是 tname 类型的 userdata。luaL_checkudata 首先将 narg 转换为 userdata ,然后获得元表;同时,从注册表中根据 tname 获得元表,两者相互比较如果不同触发错误并返回 NULL,如果相同则返回 narg 指向的 userdata。
可以看 luaL_checkudata 代码实现,非常简单。
3. luaL_newmetatable
1 | int luaL_newmetatable (lua_State *L, const char *tname); |
创建一个新的可以作为 userdata 类型元表的 table,并使用 tname 作为 key 存储在注册表中。如果注册表中已经存在 tname 类型的值,返回值为 0。
4. luaL_getmetatable
1 | void luaL_getmetatable (lua_State *L, const char *tname); |
将注册表中与名称 tname 关联的元表压入栈中。
5. lua_setmetatable
1 | int lua_setmetatable (lua_State *L, int index); |
从栈顶弹出一个 table 并将其设置为栈中 index 索引出的值的元表。