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 ...
随机推荐
- Swift和Objective-C混编的注意啦
文/仁伯安(授权) 原文链接:http://www.jianshu.com/p/2ed48b954612 前言 Swift已推出数年,与Objective-C相比Swift的语言机制及使用简易程度上更 ...
- 关于android.view.WindowLeaked(窗体泄露)的解决方案
虽然是小问题一个,但也困扰了我一段时间,现在记下来,给自己做个备忘,也可以给其他人一个参考 view plaincopy to clipboardprint? 01-08 01:49:27.874: ...
- 【jquery】hover方法
方法名称:hover(over, out) 概述:当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数.当鼠标移出这个元素时,会触发指定的第二个函数. 参数: 1) overFunction 鼠标 ...
- FreeSWITCH检测DTMF数据的方法
一.RFC2833 1. 介绍: RFC2833为带内检测方式,通过RTP传输,由特殊的rtpPayloadType即TeleponeEvent来标示RFC2833数据包.同一个DTMF按键通常会对应 ...
- 如何把scratch转成一个swf文件或者exe执行文件
scratch作为一款启蒙用的积木式编程软件,非常受人欢迎,但是,现在有一个问题就是,无法将之转变成一个可执行文件,以便和周边的人们分享. 我个人认为把scratch转变为一个可执行的exe文件,并不 ...
- AI、机器学习、深度学习、神经网络
1.AI:人工智能(Artificial Intelligence) 2.机器学习:(Machine Learning, ML) 3.深度学习:Deep Learning 人工功能的实现是让机器自己学 ...
- C# 遍历枚举(枚举是目的,遍历(获取)是手段)
C# 遍历枚举 C#中,如何获取(遍历)枚举中所有的值: public enum Suits { Spades, Hearts, Clubs, Diamonds, NumSuits } priva ...
- 如何对多个文件进行MODELSIM仿真? (由于是一个很大的项目,不可能把所有MODULE都放在一个文件里。 如何在ModelSim中对多个.V文件进行仿真?)
可以将所有要编译的所有文件的名字做一个list.新建一个文本文档,重命名为vflist vflist内容例子如下(src为文件夹):src/base_addr_chk.vsrc/config_mux. ...
- 【Android】8.1 主题基本用法
分类:C#.Android.VS2015: 创建日期:2016-02-17 一.创建本章示例主界面 1.界面截图 2.MainActivity.cs文件中对应的代码 在CreateChItems()方 ...
- 【Android】3.9 覆盖物功能
分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 百度地图SDK所提供的地图等级为3-19级(3.7.1版本中有些部分已经提供到了21级),所包含的信 ...