Userdata
我们首先关心的是如何在Lua中表示数组的值。Lua为这种情况提供专门提供一个基本的类型:userdata。一个userdatum提供了一个在Lua中没有预定义操作的raw内存区域。
Lua API提供了下面的函数用来创建一个userdatum:
void *lua_newuserdata (lua_State *L, size_t size);
lua_newuserdata函数按照指定的大小分配一块内存,将对应的userdatum放到栈内,并返回内存块的地址。如果出于某些原因你需要通过其他的方法分配内存的话,很容易创建一个指针大小的userdatum,然后将指向实际内存块的指针保存到userdatum里。我们将在下一章看到这种技术的例子。
使用lua_newuserdata函数,创建新数组的函数实现如下:
static int newarray (lua_State *L) {
int n = luaL_checkint(L, 1);
size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double);
NumArray *a = (NumArray *)lua_newuserdata(L, nbytes);
a->size = n;
return 1; /* new userdatum is already on the stack */
}
(函数luaL_checkint是用来检查整数的luaL_checknumber的变体)一旦newarray在Lua中被注册之后,你就可以使用类似a = array.new(1000)的语句创建一个新的数组了。
为了存储元素,我们使用类似array.set(array, index, value)调用,后面我们将看到如何使用metatables来支持常规的写法array[index] = value。对于这两种写法,下面的函数是一样的,数组下标从1开始:
static int setarray (lua_State *L) {
NumArray *a = (NumArray *)lua_touserdata(L, 1);
int index = luaL_checkint(L, 2);
double value = luaL_checknumber(L, 3);
luaL_argcheck(L, a != NULL, 1, "`array' expected");
luaL_argcheck(L, 1 <= index && index <= a->size, 2,
"index out of range");
a->values[index-1] = value;
return 0;
}
luaL_argcheck函数检查给定的条件,如果有必要的话抛出错误。因此,如果我们使用错误的参数调用setarray,我们将得到一个错误信息:
array.set(a, 11, 0)
--> stdin:1: bad argument #1 to 'set' ('array' expected)
下面的函数获取一个数组元素:
static int getarray (lua_State *L) {
NumArray *a = (NumArray *)lua_touserdata(L, 1);
int index = luaL_checkint(L, 2);
luaL_argcheck(L, a != NULL, 1, "'array' expected");
luaL_argcheck(L, 1 <= index && index <= a->size, 2,
"index out of range");
lua_pushnumber(L, a->values[index-1]);
return 1;
}
我们定义另一个函数来获取数组的大小:
static int getsize (lua_State *L) {
NumArray *a = (NumArray *)lua_touserdata(L, 1);
luaL_argcheck(L, a != NULL, 1, "`array' expected");
lua_pushnumber(L, a->size);
return 1;
}
最后,我们需要一些额外的代码来初始化我们的库:
static const struct luaL_reg arraylib [] = {
{"new", newarray},
{"set", setarray},
{"get", getarray},
{"size", getsize},
{NULL, NULL}
};
int luaopen_array (lua_State *L) {
luaL_openlib(L, "array", arraylib, 0);
return 1;
}
这儿我们再次使用了辅助库的luaL_openlib函数,他根据给定的名字创建一个表,并使用arraylib数组中的name-function对填充这个表。
打开上面定义的库之后,我们就可以在Lua中使用我们新定义的类型了:
a = array.new(1000)
print(a) --> userdata: 0x8064d48
print(array.size(a)) --> 1000
for i=1,1000 do
array.set(a, i, 1/i)
end
print(array.get(a, 10)) --> 0.1
在一个Pentium/Linux环境中运行这个程序,一个有100K元素的数组大概占用800KB的内存,同样的条件由Lua 表实现的数组需要1.5MB的内存。
Userdata的更多相关文章
- Lua 之 userdata
Lua 之 userdata 在Lua中可以通过自定义类型(user data)与C语言代码更高效.更灵活的交互,从而扩展Lua能够表达的类型. full userdata full userdata ...
- 快速编译system.img、userdata.img、boot.img的方法
快速编译system.img和boot.img的方法 快速编译system.img,可以使用这个命令: #make systemimage 快速编译boot.img,可以使用以下命令: #make b ...
- zImage.img、ramdisk.img、system.img、userdata.img介绍及解包、打包方法
ramdisk.img system.img userdata.img介绍及解包.打包方法 Android 源码编译后,在out/target/product/generic下生成ramdisk.im ...
- Android 的 ramdisk.img、system.img、userdata.img 作用说明,以及UBoot 系统启动过程
首先通過編譯,先將android內核編譯成功.正常情況下,在目錄out/target.product/generic/(但是有的就沒有generic文件,如freescale和iriver:但是lon ...
- Qt之界面数据存储与获取(使用setUserData()和userData())
在GUI开发中,往往需要在界面中存储一些有用的数据,这些数据可以来配置文件.注册表.数据库.或者是server. 无论来自哪里,这些数据对于用户来说都是至关重要的,它们在交互过程中大部分都会被用到,例 ...
- localstorage || globalStorage || userData
globalStorage 这个也是html5中提出来,在浏览器关闭以后,使用globalStorage存储的信息仍能够保留下来,并且存储容量比IE的userdata大得多,一个域下面是5120k.和 ...
- js本地存储解决方案(localStorage与userData)
WEB应用的快速发展,是的本地存储一些数据也成为一种重要的需求,实现的方案也有很多,最普通的就是cookie了,大家也经常都用,但是cookie的缺点是显而易见的,其他的方案比如:IE6以上的user ...
- 基于'sessionStorage'与'userData'的类session存储
Storage.js: 注意:此版本实现的存储在符合Web存储标准(ie8及ie8以上的版本与其他主流浏览器)的情况下与session的周期一致,但在页面不关闭的情况下没有过期时间,ie7及以下版本则 ...
- web本地存储-UserData
userData,IE中持久化用户数据的方法. 使用userData用户数据首先必须使用css指定userData行为.代码示例: var ud = document.createElement(&q ...
- Lua中的userdata
[话从这里说起] 在我发表<Lua中的类型与值>这篇文章时,就有读者给我留言了,说:你应该好好总结一下Lua中的function和userdata类型.现在是时候总结了.对于functio ...
随机推荐
- WordPress网站搬家经验总结
http://cnzhx.net/blog/move-wordpress-site-step-by-step/也许很多人都有跟我类似的经历:因为某种原因需要将自己的WordPress站点从一个空间转移 ...
- 百度UEditor富文本编辑器去除过滤div等标签
将设计排版好的页面html代码上传到数据库,再读取出来的时候发现所有的div都被替换成了p标签. 解决方法: 首先在ueditor.all.js文件内搜索allowDivTransToP,找到如下的代 ...
- Redis下载和安装
原文地址:https://redis.io/download Download Redis uses a standard practice for its versioning: major.min ...
- 《JAVA与模式》之适配器模式(转载)
适配器模式比较简单,偷个懒,直接转载一篇. 个人理解: * 类适配器是通过继承来完成适配 * 对象适配器是通过传递对象来完成适配 * 不管哪种,其实都是通过引用特殊接口的对象来完成特殊接口的适配调用 ...
- Android 弹出有确认按键的对话
//弹出对话框-------------------------------------------------- private void openDialog(String strMsg, Str ...
- Kruskal算法 - C语言详解
最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树. 例如,对于如上图G4所示的连通网可以有多棵权值总 ...
- 统计学习方法:支撑向量机(SVM)
作者:桂. 时间:2017-05-13 21:52:14 链接:http://www.cnblogs.com/xingshansi/p/6850684.html 前言 主要记录SVM的相关知识,参考 ...
- MySQL Study之--MySQL下图形工具的使用(MySQL Administrator)
MySQL Study之--MySQL下图形工具的使用(MySQL Administrator) 系统环境: 操作系统: Windows 7(64) 下载地址:http://www.soft ...
- Web学习篇之---html基础知识(一)
html基础知识(一) 本篇文章主要介绍HTML头部所包括的信息. 一.下面都是在标签<head>...</head>之间的内容: 1.<title>-</t ...
- Modelsim编译Xilinx器件库的另一种方法
由 xooo 于 星期五, 09/18/2015 - 15:35 发表 以前在用modelsim对Xilinx进行器件库编译时,我用的比较多的是直接在ISE中编译器件库,感觉很方便简单,就是编译时间有 ...