我们首先关心的是如何在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的更多相关文章

  1. Lua 之 userdata

    Lua 之 userdata 在Lua中可以通过自定义类型(user data)与C语言代码更高效.更灵活的交互,从而扩展Lua能够表达的类型. full userdata full userdata ...

  2. 快速编译system.img、userdata.img、boot.img的方法

    快速编译system.img和boot.img的方法 快速编译system.img,可以使用这个命令: #make systemimage 快速编译boot.img,可以使用以下命令: #make b ...

  3. zImage.img、ramdisk.img、system.img、userdata.img介绍及解包、打包方法

    ramdisk.img system.img userdata.img介绍及解包.打包方法 Android 源码编译后,在out/target/product/generic下生成ramdisk.im ...

  4. Android 的 ramdisk.img、system.img、userdata.img 作用说明,以及UBoot 系统启动过程

    首先通過編譯,先將android內核編譯成功.正常情況下,在目錄out/target.product/generic/(但是有的就沒有generic文件,如freescale和iriver:但是lon ...

  5. Qt之界面数据存储与获取(使用setUserData()和userData())

    在GUI开发中,往往需要在界面中存储一些有用的数据,这些数据可以来配置文件.注册表.数据库.或者是server. 无论来自哪里,这些数据对于用户来说都是至关重要的,它们在交互过程中大部分都会被用到,例 ...

  6. localstorage || globalStorage || userData

    globalStorage 这个也是html5中提出来,在浏览器关闭以后,使用globalStorage存储的信息仍能够保留下来,并且存储容量比IE的userdata大得多,一个域下面是5120k.和 ...

  7. js本地存储解决方案(localStorage与userData)

    WEB应用的快速发展,是的本地存储一些数据也成为一种重要的需求,实现的方案也有很多,最普通的就是cookie了,大家也经常都用,但是cookie的缺点是显而易见的,其他的方案比如:IE6以上的user ...

  8. 基于'sessionStorage'与'userData'的类session存储

    Storage.js: 注意:此版本实现的存储在符合Web存储标准(ie8及ie8以上的版本与其他主流浏览器)的情况下与session的周期一致,但在页面不关闭的情况下没有过期时间,ie7及以下版本则 ...

  9. web本地存储-UserData

    userData,IE中持久化用户数据的方法. 使用userData用户数据首先必须使用css指定userData行为.代码示例: var ud = document.createElement(&q ...

  10. Lua中的userdata

    [话从这里说起] 在我发表<Lua中的类型与值>这篇文章时,就有读者给我留言了,说:你应该好好总结一下Lua中的function和userdata类型.现在是时候总结了.对于functio ...

随机推荐

  1. Python程序数据溢出问题或出现 NAN 问题

    [数据溢出问题] overflow:溢出 overflow:上溢 underflow:下溢 数据溢出包括上溢和下溢. 上溢可以理解为:你想用一个int类型来保存一个非常非常大的数,而这个超出了int类 ...

  2. 分布式缓存技术memcached学习系列(五)—— memcached java客户端的使用

    Memcached的客户端简介 我们已经知道,memcached是一套分布式的缓存系统,memcached的服务端只是缓存数据的地方,并不能实现分布式,而memcached的客户端才是实现分布式的地方 ...

  3. postgresql命令行[转]

    postgresql命令行 原文链接 PostgreSQL 8.1 中文文档 连接数据库, 默认的用户和数据库是postgrespsql -U user -d dbname \c dbname 切换数 ...

  4. C# 调节图片亮度

    原文地址:https://www.cnblogs.com/wjr408/p/6727118.html 昨天去客户那里测试,需求才开始,所以很简单,就是测一下能不能接受到视频或图片,然后保存下来,现场客 ...

  5. 为什么百度首页的HTML源代码最后一行要多一行?浪费空间呀!

     为什么百度首页的HTML源代码最后一行要多一行?浪费空间呀!

  6. [转]Google 全球 IP 地址库

    IP 地址来源:http://www.kookle.co.nr Bulgaria 93.123.23.1 93.123.23.2 93.123.23.3 93.123.23.4 93.123.23.5 ...

  7. 使struct对象拥有可变大小的数组——(C++深度探索)

    首先摘录<Inside The C++ Object Model>中的一段话: 把单一元素的数组放在一个struct的尾端,于是每个 struct objects 可以拥有可变大小的数组: ...

  8. iOS学习笔记37-时间和日期计算

    一.时间和日期计算 我们在应用开发中,时常须要和时间打交道,比方获取当前时间,获取两个时间点相隔的时间等等,在iOS开发中与时间相关的类有例如以下几个: 1. NSDate:表示一个绝对的时间点 2. ...

  9. angular学习笔记(二十五)-$http(3)-转换请求和响应格式

    本篇主要讲解$http(config)的config中的tranformRequest项和transformResponse项 1. transformRequest: $http({ transfo ...

  10. python 使用py2exe将python 脚本生成exe可执行文件

    使用python的py2exe模块可以很容易地帮助我们将python脚本生成可执行的exe程序.这样我们就可以让脚本脱离虚拟机的束缚,从而独立运行. 首先安装py2exe分解步骤如下:(pip和eas ...